You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

调用IMFSourceReader::ReadSample线程卡住,如何用TerminateThread终止?

问题描述

调用IMFSourceReader::ReadSample时,遇到无法读取数据的情况,线程会卡住。尝试用TerminateThread()终止线程,但返回0(操作失败),错误码为6。另外尝试pthread_cancel时出现编译错误:

no suitable constructor exists to convert from "std::thread::native_handle_type" to "__ptw32_handle_t"

以下是示例代码:

#include <iostream>
#include <vector>
#include <codecvt>
#include <string>
#include <thread>
#include <mutex>
#include <chrono>
#include <condition_variable>
#include <Windows.h>

using namespace std::chrono_literals;

class MyObject
{
private:
    ...

    std::thread *t;
    std::mutex m;
    std::condition_variable cv;
    std::thread::native_handle_type handle;

    int getsample(uint8_t* data)
    {
        // call a ReadSample
        hr = pVideoReader->ReadSample(
              MF_SOURCE_READER_ANY_STREAM,    // Stream index.
              0,                              // Flags.
              &streamIndex,                   // Receives the actual stream index. 
              &flags,                         // Receives status flags.
              &llTimeStamp,                   // Receives the time stamp.
              &pSample                        // Receives the sample or NULL.
        );

        ...

        return 0;
    }
    int myfunc_wrapper(uint8_t* data)
    {
        int ret = 0;
        BOOL bpass = 0;

        if (t == nullptr) {
            t = new std::thread([this, &data, &ret]()
                {
                    ret = this->getsample(data);
                    this->cv.notify_one();
                });
            handle = t->native_handle();
            t->detach();
        }

        {
            std::unique_lock<std::mutex> l(this->m);

            if (this->cv.wait_for(l, 2500ms) == std::cv_status::timeout) {
                bpass = TerminateThread(handle, 0);
                if (bpass == 0) {
                    std::cout << "TerminateThread Fail! " << GetLastError() << std::endl;
                }
                throw std::runtime_error("Timeout Fail 2500 ms");
            }
        }

        delete t;
        t = nullptr;
    }

public:

    int my_func(uint8_t* raw_data)
    {
        bool timedout = false;

        try {
            if (myfunc_wrapper(raw_data) != 0)
                return -1;
        }
        catch (std::runtime_error& e) {
            std::cout << e.what() << std::endl;
            timedout = true;
        }

        if (timedout)
            return -1;

        return 0;
    }
};

int main()
{
    uint8_t data[512];
    MyObject* obj = new MyObject();

    while (true)
    {
        obj->my_func(data);
    }

    return 0;
}

程序输出:

TerminateThread Fail! 6
Timeout Fail 2500 ms
TerminateThread Fail! 6
Timeout Fail 2500 ms
...
解决方案

1. 分析TerminateThread失败原因

错误码6对应ERROR_INVALID_HANDLE,说明传入的线程句柄无效,问题出在:

  • 调用t->detach()后,std::thread对象不再管理线程,native_handle()返回的句柄可能已失效或被系统回收资源。
  • detach后执行delete t,直接销毁std::thread对象,但线程本身仍在运行,进一步导致句柄失效。

2. 优先采用优雅终止方案(不推荐暴力终止)

TerminateThread属于危险操作,可能引发内存泄漏、资源无法释放(如Media Foundation的COM对象)甚至进程崩溃,优先用以下原生机制:

方法一:改用IMFSourceReader异步读取模式

Media Foundation推荐异步读取样本,从根源避免线程阻塞,还能优雅终止:

  1. 调用IMFSourceReader::SetCallback设置回调对象,实现IMFSourceReaderCallback接口。
  2. 需要终止时,调用IMFSourceReader::CancelAllPendingReads取消所有未完成的读取请求,线程会自然退出。

方法二:同步读取模式下增加终止信号

在类中添加原子布尔变量std::atomic<bool> should_exit,在线程逻辑中检查该变量,同时用CancelAllPendingReads中断ReadSample的阻塞:

class MyObject
{
private:
    std::atomic<bool> should_exit = false;
    IMFSourceReader* pVideoReader = nullptr;
    // ...其他成员

    int getsample(uint8_t* data)
    {
        while (!should_exit)
        {
            if (should_exit) break;

            HRESULT hr = pVideoReader->ReadSample(
                MF_SOURCE_READER_ANY_STREAM,
                0,
                &streamIndex,
                &flags,
                &llTimeStamp,
                &pSample
            );

            if (FAILED(hr)) break;
            // ...处理样本逻辑
        }
        return 0;
    }

    int myfunc_wrapper(uint8_t* data)
    {
        int ret = 0;
        should_exit = false;

        std::thread t([this, data, &ret]()
        {
            ret = this->getsample(data);
            this->cv.notify_one();
        });

        {
            std::unique_lock<std::mutex> l(m);
            if (cv.wait_for(l, 2500ms) == std::cv_status::timeout)
            {
                if (pVideoReader)
                {
                    pVideoReader->CancelAllPendingReads();
                }
                should_exit = true;
                t.join();
                throw std::runtime_error("Timeout Fail 2500 ms");
            }
        }

        t.join();
        return ret;
    }
    // ...其他代码
};

方法三:修正句柄问题(仅作为最后手段)

如果必须用TerminateThread,需保证句柄有效:

  • 不要调用t->detach(),保留std::thread对象直到线程终止。
  • 用DuplicateHandle复制线程句柄,避免原句柄被销毁:
// 创建线程后
HANDLE thread_handle = t->native_handle();
HANDLE dup_handle;
DuplicateHandle(GetCurrentProcess(), thread_handle, GetCurrentProcess(), &dup_handle, 0, FALSE, DUPLICATE_SAME_ACCESS);
// 使用dup_handle调用TerminateThread
TerminateThread(dup_handle, 0);
// 用完后关闭复制的句柄
CloseHandle(dup_handle);

注意:即使修正句柄,暴力终止仍可能引发资源泄漏,不建议使用。

3. 关于pthread_cancel的问题

Windows下std::thread的native_handle是Win32线程句柄,而pthread_cancel是POSIX线程库函数,两者不兼容,因此出现编译错误。Windows环境下应使用Win32线程API,不要混用POSIX接口。

内容的提问来源于stack exchange,提问作者Verizz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 08:40:31