Qt界面开发纪实:Qt 计时器 多线程加锁 C++差错控制 try throw 与catch(QT C++ MSVC MinGW )(2)

Qt界面开发纪实:Qt 计时器 多线程加锁 C++差错控制 try throw 与catch(QT C++ MSVC MinGW )(2)

    • Qt 计时器Qtimer
    • 线程锁
    • 差错控制 throw与try 和catch

上一篇博客 https://blog.csdn.net/TiffanyXYf/article/details/100011341 中主要介绍了开发工具的配置,信号与槽,以及简略地说明了多线程实现界面刷新。本篇博客继续记录采坑事件。

Qt 计时器Qtimer

根据甲方爸爸对于显示界面刷新的要求,其中有一项功能是:实现每0.2s刷新一次界面 实现这个功能最简单的方式就是使用一个计时器,让这个计时器不断地每0.2s触发一次槽函数(显示图片),从而实现界面0.2s刷新一次界面。Qtimer的使用包括三部分:1.定义一个计时器,2.将计时器的timeout()函数与一个对应的槽函数配对(我这里需要将timeout函数与某一个子线程的槽函数相连,因为需要显示的图片来自子线程,这个sing_imgprocess()函数还会发出其他信号函数,从而触发主线程刷新界面),3.启动计时器(如图直接start即可)。
头文件:#include
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
计时器这里遇到的一个坑:多线程如果访问了同一个变量的话,系统会出现内存访问冲突。我刚接触多线程,没有帮线程加锁。在实现0.2s刷新之前,一个子线程+一个主线程是可以连续稳定运行的。但是写了0.2s刷新之后,我的代码开始变得不稳定,以随机时间长度崩溃,短则30分钟,长则4个小时以上。 后来师弟发现在Qt项目中,即使两个线程一起读一个变量也需要加锁,加了锁之后,上述问题依旧没有解决。大概过了一周,发现是上图:timeout对应的那个槽函数漏掉加锁了
那个函数原来的定义是:判断是否0.2s刷新以及要显示的这个图片是否为空,然后直接发信号给主线程显示。其中showImg是线程类中的一个成员,所以可以在线程对象中可以修改和使用
Qt界面开发纪实:Qt 计时器 多线程加锁 C++差错控制 try throw 与catch(QT C++ MSVC MinGW )(2)_第1张图片
加锁之后,这个函数变成:核心思想就是访问某个可能被多个函数使用的变量时,将其锁住,拷贝成另一个变量,再使用另外一个变量进行操作,从而避免访问冲突,下图就是一个例子。
Qt界面开发纪实:Qt 计时器 多线程加锁 C++差错控制 try throw 与catch(QT C++ MSVC MinGW )(2)_第2张图片

线程锁

上一部分提到了给变量加锁,这一部分具体说说怎么使用这个锁(我这里使用的时最基础的锁,Qt中还存在别的更高端的锁,如果感兴趣可以去网上查看)

首先:锁是一个全局变量,我有多个cpp文件需要用到锁,所以声明锁的时候要用extern这里涉及到一个知识点:如何再多个cpp文件中使用同一个变量

例如,在A.h文件中声明了一个锁
在这里插入图片描述
在A.cpp中再次声明一下
在这里插入图片描述
如果在A.cpp中没有声明的话编译时会报错:
在这里插入图片描述
在B.cpp中需要用到这个锁:
则可以直接在B.cpp中include A.h,这样就可以直接使用,而不需要在B.cpp中重新声明。

使用锁也很简单
多个线程需要用同一个锁,只需要在线程类中声明一个锁,然后建立线程的时候将所有的锁都指向这个全局的锁

如图:
B.h中定义一个锁:
Qt界面开发纪实:Qt 计时器 多线程加锁 C++差错控制 try throw 与catch(QT C++ MSVC MinGW )(2)_第3张图片
B.cpp 中指向全局锁mutex1
Qt界面开发纪实:Qt 计时器 多线程加锁 C++差错控制 try throw 与catch(QT C++ MSVC MinGW )(2)_第4张图片
B.cpp 中,其他函数需要使用锁时:直接对需要的变量进行lock 和unlock就行了。
Qt界面开发纪实:Qt 计时器 多线程加锁 C++差错控制 try throw 与catch(QT C++ MSVC MinGW )(2)_第5张图片
需要说明的是:我使用的这个锁比较基础,lock和unlock必须是配对使用的,如果存在锁住的代码中有return或者throw的操作,导致只执行了lock而没有执行unlock会导致死锁。 Qt中有其他的锁,可以在上述特殊情况下,自动执行一个函数,使其unlock,由于没有使用,我这里就不多说了。
总之,通过对线程加锁,我的代码随机闪退的情况得到了解决。而且不知道为什么这里两个线程同时读也需要加锁,而一般“读读”是不需要加锁的

差错控制 throw与try 和catch

相机操作和图像处理过程中会存在很多异常情况,比如相机采集图片时遇到残帧,图片处理的图片质量达不到要求。差错控制的目的是保证程序在遇到这些异常情况的时候依然能运行下去

throw可以扔出任何类型的错误,甚至结构体,类都可以被抛出,但是一般不需要那么麻烦。
我使用的有两种:相机相关的错误和图片处理相关的错误
string camera_err=“camera_err”;
throw(camera_err)

int image_err=111;
throw(image_err);

try
{…执行的程序}
catch(camera_err){…你的处理}
catch(image_err){…你的处理}

这样只要差错能够被catch到,程序运行就不会受到影响
有可能的坑:如果你throw了一个错误,但是没有catch,则程序会在throw那里直接退出,或者报严重的错误,所以自己定义的差错,一定要记得都catch。

下一篇:会接着介绍学会的操作与遇到的坑

你可能感兴趣的:(OpenCV,VS2017,Qt)