C++使用相机子线程与虚拟相机时程序无法正常关闭,出现挂起或异常
问题根源和修复方案
现存问题点
- 跨线程访问的
go3变量是普通非原子类型,存在数据竞争,属于C++未定义行为,可能导致循环退出条件不生效 - 线程调用了
detach()脱离主线程管控,主线程退出时进程地址空间会被直接回收,此时仍在运行的后台线程访问已销毁的资源会直接触发崩溃 - 退出逻辑完全错误:设置
go3 = 1后立刻判断is_done == true,此时工作线程还没来得及执行到修改is_done的逻辑,判断永远不成立,主线程会直接退出,不会等待工作线程完成清理 - 工作线程退出循环后没有释放申请的资源:
cv::VideoCapture、scCamera没有执行对应的销毁逻辑,可能导致资源锁死或者退出异常 - 若
scSendFrame/cap.read存在阻塞逻辑,工作线程可能长时间卡在调用中无法及时检查退出条件
修复步骤
- 把
go3改为原子类型,消除数据竞争
// 原int go3 = 0; 修改为: std::atomic<int> go3 = 0;
- 移除
thread2.detach(),改为退出前主动join等待线程结束,不要依赖不可靠的sleep和is_done判断 - 工作线程退出循环后增加资源清理逻辑
- 可选:如果
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
相关产品推荐
相关产品推荐

