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

C++使用相机子线程与虚拟相机时程序无法正常关闭,出现挂起或异常

问题根源和修复方案

现存问题点

  • 跨线程访问的go3变量是普通非原子类型,存在数据竞争,属于C++未定义行为,可能导致循环退出条件不生效
  • 线程调用了detach()脱离主线程管控,主线程退出时进程地址空间会被直接回收,此时仍在运行的后台线程访问已销毁的资源会直接触发崩溃
  • 退出逻辑完全错误:设置go3 = 1后立刻判断is_done == true,此时工作线程还没来得及执行到修改is_done的逻辑,判断永远不成立,主线程会直接退出,不会等待工作线程完成清理
  • 工作线程退出循环后没有释放申请的资源:cv::VideoCapture、scCamera没有执行对应的销毁逻辑,可能导致资源锁死或者退出异常
  • 若scSendFrame/cap.read存在阻塞逻辑,工作线程可能长时间卡在调用中无法及时检查退出条件

修复步骤

  1. 把go3改为原子类型,消除数据竞争
// 原int go3 = 0; 修改为:
std::atomic<int> go3 = 0;
  1. 移除thread2.detach(),改为退出前主动join等待线程结束,不要依赖不可靠的sleep和is_done判断
  2. 工作线程退出循环后增加资源清理逻辑
  3. 可选:如果cap.read/scSendFrame存在长时间阻塞,可以考虑拆分逻辑、增加超时判断,保证退出条件可以被及时检查

修改后的参考代码

std::atomic<int> go3 = 0;

int camera() {
    const int WIDTH = 640;
    const int HEIGHT = 480;
    cv::VideoCapture cap(1);
    if(!cap.isOpened()) {
        return -1;
    }
    cap.set(cv::CAP_PROP_FRAME_WIDTH, 640);
    cap.set(cv::CAP_PROP_FRAME_HEIGHT, 480);
    cap.set(cv::CAP_PROP_FPS, 60);
    cv::Mat frame;
    cv::Mat srcImage = cv::imread("img/zoom log_50sm.png", -1);
    // 增加图片读取成功校验,避免后续空访问崩溃
    if(srcImage.empty()) {
        // 按需处理读失败逻辑
    }
    cv::Mat mask;
    vector<cv::Mat> rgbLayer;

    scCamera cam = scCreateCamera(WIDTH, HEIGHT, 60);
    scWaitForConnection(cam);

    while (go3 != 1)
    {
        if(!cap.read(frame)) {
            // 读帧失败可以退出或者重试
            break;
        }
        scSendFrame(cam, frame.ptr());
    }

    // 退出后清理资源
    scReleaseCamera(cam); // 请替换为你所用SDK对应的虚拟相机销毁函数
    cap.release();
    return 0;
}

int main() {
    std::thread thread2(camera);
    MyApp app;
    app.Run();
    // 通知工作线程退出
    go3 = 1;
    // 等待工作线程完全退出再结束主线程
    if(thread2.joinable()) {
        thread2.join();
    }
    return 0;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 11:06:04