由“Qt程序运行一段时间后崩溃”引发的“opancv库中Mat::clone()函数”在多线程下的注意事项
Posted neolin
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了由“Qt程序运行一段时间后崩溃”引发的“opancv库中Mat::clone()函数”在多线程下的注意事项相关的知识,希望对你有一定的参考价值。
- 问题描述
- 过程1:从相机中获取图像数据,然后存放到一个cv::Mat对象中(该对象是全局变量,用来交换数据)。由相机的回调函数自动调用。
- 过程2:将上述的全局变量拷贝并转换qimg,放到Qt界面上显示。该过程由定时器调用。
- 然后程序会在运行一段时间后,出现“程序异常结束。The process was ended forcefully.”。运行的时间长短不一。
- 问题解决与分析
- 由于QtCreator的编译器选的是MSVC,而调试器选只有GDB(查了下好像需要CDB)。所以无法debug,只能一点点排查。
- 测试定时器时间越短,出现问题越快。猜测是多线程下访问冲突。
- 输出线程id查看,使用std::this_thread::get_id()获取当前线程的ID,发现相机写入Mat对象的过程的线程号 和 定时器调用的读取Mat对象的线程号不一样。这说明相机的SDK在获取图像数据的部分是创建了新的线程进行的。
- 可是读写应该不冲突,所以看看opencv的Mat::clone()方法。
inline Mat Mat::clone() const Mat m; copyTo(m); return m; // 噢 原来是调用的cv::copyTo方法,等等,上面有个const,这下明白了,在拷贝的时候是不允许修改值的,如果正在拷贝,此时相机写入线程正好获取了相机数据,准备写入,这时就发生了冲突。总之读写不能同时进行。 //那么就是用互斥量将两者互斥, #include <mutex> std::mutex mtx; //在读(Mat::clone()) / 写 之前使用mtx.lock();,之后使用mtx.unlock(); 问题解决啦。
- 最后测试是否真的是这个原因。声明一个槽函数,连接上某按钮的click动作。调用.clone()并且没有加锁。
void QtGuiApplication1::on_btnThread_clicked()
auto myThread = []
while (1)
if (!temp_forSave.empty())
Mat lalala = temp_forSave.clone();
std::cout << "在创建线程中复制\\n";
std::cout << "创建线程" << std::this_thread::get_id() << "运行" << endl;
;
std::thread a(myThread);
a.join();
- 正常运行时,点击按钮程序立即崩溃(毕竟该线程时while(1)地拷贝)。验证成功。
以上是关于由“Qt程序运行一段时间后崩溃”引发的“opancv库中Mat::clone()函数”在多线程下的注意事项的主要内容,如果未能解决你的问题,请参考以下文章
由View的onAttachedToWindow引发的图片轮播问题探究