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
|