Boost与Qt的信号/槽及执行线程

发布: 2011-09-04 21:38

Boost与Qt均提供了线程功能,信号/槽功能,
但Qt有自己的事件循环功能,Boost没有自带的事件循环,如需要使用的话,需要自己实现。

Qt的了自带的事件循环,但在使用的时候可能与某些库的线程有冲突,
最近遇到一个此种类型的奇怪问题,没有找到问题所在,也没有好的解决方法。

经过多次测试,理清了Boost与Qt的信号/槽及执行线程之间的一些关系,记录下这些规律以备份后用、讨论。


针对这个Qt事件循环冲突的问题,设计了一个GUI应用程序的架构,说来也比较简单,把GUI线程与核心功能模块分离,GUI相关操作在Qt的事件循环中执行,核心功能在另一自己编写的简单boost线程中执行。
两模块之间的通信不是使用的直接的函数调用实现,而时使用实现了异步调用,相互之间不会有任何事件交叉,不会引起问题。异步调用有两种方式,可以使用两者的信号/槽,或者可以使用一些进程间通信(IPC,SOCKET,管道,消息队列,共享内存)的功能。

在本次测试实现中,由于功能的需要,两种方式都实现了相应的功能。

第一种,使用信号/槽的方法,
这种方法同时涉及了Qt与Boost的信号/槽,则会遇到一个新的实际问题,信号在一线程中发出,却希望对应的槽在另一模块的线程中执行。
默认情况下Qt发出的信号对应的槽会在发出信号的线程执行,
Boost发出的信号对应的槽也会在发出信号的线程执行。
如果这么运行的话,一个复杂的处理可能导致GUI界面冻结,而如果把boost线程需要改变GUI界面时,很容易导致程序崩溃。

这时,需要中间组件,负责把信号的槽转到需要的线程执行。

目前设计了一个继承自QObject的类BoostBridge,没有实现任何的实现功能,只是用来传递双方的信号。该类从GUI线程实例化,当来自Boost的信号执行了该实例的一个方法(也就是Boost信号的槽),在这个方法中发射一个Qt信号,等这个Qt信号的槽执行时,它已经运行于Qt 的事件循环线程了。

当需要从Qt线程发射信号到Boost线程时,有点复杂了,因为在该类的实现中发送Boost的信号时,实际上该信号的槽还是在Qt线程中执行的。多亏了有boost::function功能,在发送Boost信号的时候,把相应的回调槽使用boost::function包装,相当于把一个数据变量传递过去,存储在某个boost线程可读取到的变量中,然后在boost线程循环中读取存放信号对应回调槽并执行它,也就实现了从Qt线程发出信号,最后对信号的处理回调槽脱离Qt线程,而在Boost线程中执行的功能。

对第二种方法,使用IPC,两者的通信更独立,分别在两端的线程处理相应的事件循环即可。如socket,两个线程分别实现服务器端和客户端,在客户端线程连接到服务器socket端口,收发数据如正好的分进程的C/S程序。
在本应用中也就是使用的比较通用的socket,比较简单,两端只要定义一个简单的通信协议,也就实现了两个线程无相互之间的直接调用功能。


原文: http://qtchina.tk/?q=node/596

Powered by zexport