我们开发了一个与相机和微控制器集成的系统。 GUI显示来自摄像机的图像和来自微控制器的串行计数,我们使用串行线程轮询微控制器的数据,并将信号发送到GUI进行显示,此外,我们还使用了单独的线程来捕获图像并将其传递给主控制器线。 应用程序的问题是,当系统处于空闲状态时,GUI冻结,我们必须重新启动应用程序才能开始工作(无用的意思是,用户未租赁任何按钮,并且计数和图像不断出现)。 这里最要注意的是GUI冻结问题在这里不一致。已安装了多个系统,在某些地方,冻结(不响应)问题每2/3周出现一次,在某些地方,则是2天出现一次。等待应用程序响应无济于事。
我的主要问题是GUI冻结的主要原因是什么,是否需要对串行线程和图像捕获线程进行任何检查,以避免不必要的数据散发。
答案 0 :(得分:1)
像您这样的声音正在经历并发冲突,并不一定会导致崩溃,直到事情运行了足够长的时间才能最终击中恰好在适当时候发生的事件的魔术组合。
您的应用程序中包含三个线程:GUI线程,串行线程和相机线程。串行和相机线程从设备收集数据,然后将它们传递到GUI线程进行显示。我认为串行线程和相机线程不会共享任何数据,因此那里没有出现问题的风险。
您如何将数据从串行和相机线程传递到GUI线程?这可能是您遇到问题的地方。
大多数复杂的数据结构和Qt类都不是线程安全的,这意味着绝对不能同时从两个或多个线程同时读取和写入它们。
以下是在线程之间安全地传递数据的一些策略:
整数在CPU的指令集级别上是原子的,因此您可以安全地读写整数(或等于或小于整数的任何数据类型,例如bool,单个char或a)。指针)从多个线程,而不会发生任何不一致的状态。您必须使用C ++的std :: atomic <>模板声明此类变量,以确保编译器不会执行破坏原子性的优化。
任何比整数大/复杂的操作都有一个线程将一半的数据写入内存的风险,而另一个线程同时读取一半的数据,从而导致非常意外的结果,经常会导致应用程序崩溃或崩溃卡在无限循环中的东西。
Qt中的信号和插槽是线程安全的。在线程之间传递复杂数据的一种方法是在一个线程中emit
,而在另一个线程中slot
则接收该数据。在这种情况下,Qt会为您解决所有潜在的并发问题。这里唯一的难题是,如果数据的使用者线程不能足够快地吸收数据,Qt的事件队列将被塞满太多数据,最终您的应用将崩溃,因为新的GUI事件(例如鼠标单击,重新绘制事件等)无法再通过堵塞的事件队列。
您可以使用QMutex
确保一次只有一个线程正在读取或写入复杂的数据结构。 QMutex
使您可以阻止/停止一个或多个线程中的执行,而单个线程“持有”互斥锁并允许其执行,对数据进行处理,而没有其他线程接触该数据的风险。当一个线程完成后,它“释放”互斥锁,然后允许其他线程之一“保留”互斥锁,恢复其执行,以便可以处理数据。
就测试而言,数据并发率越高,通常由于并发冲突而导致应用崩溃的机会就越大。如果您可以人为地增加摄像机帧的速率和“串行计数”传递给GUI线程的速度,则可以更快地重现应用程序崩溃的情况。成功解决并发问题后,您应该能够用数据充斥整个系统,而绝不会使其崩溃。