Qt线程间通信的Qt::DirectConnection疑问

yby4769250 2011-08-13 05:24:26
最近在捣腾Qt的多线程,在线程间通信这一块有点疑问,一般而言,使用全局变量或者消息机制来进行线程间通信,这里,得益于Qt的signal/slot机制,我使用使用了信号来通信。

先说一下我对基本概念的理解,从操作系统的角度去看,任一时刻,只能有一个线程在运行,基于这个观点,引出了我的问题。

我有两个线程,线程A和线程B,当A处于运行态的时候,B处于等待态,现在,我在A的运行过程中,想给B传递一些数据,我使用了Qt::DirectConnection来把A的signal连接到B的slot上,而Qt::DirectConnection的说明是直接跳到slot函数去执行slot的代码。现在的问题是,A处于运行态,B处于等待态,并且slot函数属于B线程的,通过Qt::DirectConnection怎么能够跑去执行B线程的代码呢?因为B还在等待,还没轮到B执行,难道是,操作系统先把A挂起,然后唤醒B,接着跑去执行B的slot函数?还是什么机制,因为无论如何,AB是不可能同时处于运行态的,这个Qt::DirectConnection是如何保证B的slot能够马上执行,并且保证代码安全的(而不是一个非法的强制跳转)执行呢?

基于这个问题,我还引出了另外一个问题,如果使用消息机制进行通信,线程A给线程B发送消息只能使用postEvent不能使用sendEvent,postEvent把消息放入B的消息队列中,然后A继续执行,当B运行时,就从消息队列中取出消息进行处理,这样才安全,而sendEvent是马上跑到B的消息处理函数中去处理这个消息,处理完毕后才返回,然后A继续执行,但是这个问题同开始的问题一样,当调用sendEvent时,A处于运行态,B处于等待态,要处理这个消息,必须强制从A跳到B去执行代码,这不是非法的了吗?如果B线程没有唤醒,怎么能够执行B的消息处理函数呢?而B要运行则A必然要挂起,这里就很乱了,难道操作系统会先挂起A,然后唤醒B,B处理完后,又挂起B,再唤醒回A,A从sendEvent返回处开始继续执行。

上面的问题可以简单的概括为,如何在线程外面对线程进行控制,就好比是,在B线程外面(A线程里),对B进行控制,因为一旦处在线程B外面,就表明其他线程(A)在运行态,而本身B线程在挂起,而B没有进入运行态的话,怎么控制得了它的执行序列呢?非常困惑,请教论坛里的大神门了
...全文
1122 9 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
Toshio 2013-07-13
  • 打赏
  • 举报
回复
很好的问题,也有很好的回答,线程在编程学习过程中,是个困扰绝大部分人的问题,谢谢这个帖子!
tanghp_bj 2012-07-11
  • 打赏
  • 举报
回复
沙发正解!受教了!
a724470522 2012-05-05
  • 打赏
  • 举报
回复
我也在这个问题卡主了
swift19221 2011-08-30
  • 打赏
  • 举报
回复
楼上正解, yby4769250 没有把线程对象和线程搞清楚,
很难解释清楚
dbzhang800 2011-08-13
  • 打赏
  • 举报
回复 1
更不清楚你的问题是什么了,记住一点够了:直接连接,其实就等同于直接调用。

跨线程时只有队列连接是安全的,队列连接借助的是事件系统,所以你可以通过postEvent在线程间传递数据。

如果搞不清楚slot在那个线程内执行,在那个函数内加入一句:
qDebug()<<QThread::currentThreadId();
就行了。
yby4769250 2011-08-13
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 dbzhang800 的回复:]
换个说法吧,你所说的顶楼所说的 A、B 分别是 QThread 的子类??

假定如此,你在主线程中创建了A、B像个Thread对象,它们各自维护一个线程(各自的run函数)。

然后A、B类有一些signals 或 slots 成员,由于A、B依附与主线程,当queued方式连接(或者postEvent)时,slots会在主线程执行。

假定你A有一个slots叫做 slotA,那么……
[/Quote]

跨线程queued方式连接(或者postEvent)不是在receiver线程内执行的吗?

还有,如果线程的函数是通过成员函数的方式来调用执行的话(除了start外),这个线程的设计是不是存在问题呢?
在B的run里面,要通过A.slotA()来调用slotA,需要在B内生成一个A对象,这个方式使得线程间的耦合度太高,依赖性太大,我觉得这样设计线程是不合理的。
signal/slot本质就是通信双方互相不知道,只要通信方emit,他就不用去管接收方是谁以及如何处理。
因此,上述就是emit signalA()更合理。

我个人认为,一个线程的函数都不应该在线程外面通过成员函数的方式调用执行,甚至说不能,应该都声明为slot函数,通过在run里面,调用exec来处理。当在线程外面要执行线程的某个函数的时候,只要emit即可,emit把消息放入消息队列中,当线程激活时,由exec内部来处理决定调用指定的成员函数,我认为这种方式耦合度低,模块性更强,更符合线程本身的意义。
因此,按照我设计的这种方式的话,就是要适当的考虑线程间信号与槽的链接方式了。
dbzhang800 2011-08-13
  • 打赏
  • 举报
回复
换个说法吧,你所说的顶楼所说的 A、B 分别是 QThread 的子类??

假定如此,你在主线程中创建了A、B像个Thread对象,它们各自维护一个线程(各自的run函数)。

然后A、B类有一些signals 或 slots 成员,由于A、B依附与主线程,当queued方式连接(或者postEvent)时,slots会在主线程执行。

假定你A有一个slots叫做 slotA,那么它就是一个普通的成员函数,其代码在哪儿执行,取决于该函数在那个线程调用。如此而已。

你在主线程调用 A.slotA() ,那么代码就在主线程执行,你在A所管理的线程内(run函数内)调用this->slotsA(),那么就在这个次线程内执行。如果你在B的run函数内调用A.slotsA(),那么就在B所管理的线程内执行代码。

题外:所谓的直接连接,其实就是直接调用!
yby4769250 2011-08-13
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 dbzhang800 的回复:]
基本概念错了。
假定你有两个线程 TA 和 TB,
TA、TB 内分别创建了对象 A、B

然后你在TB内调用A的成员函数,就是调用一个普通函数而已,此时和线程TA没什么关系,代码在TB内执行。

如果
[/Quote]

基本概念错了?怎么说?前提是单CPU。
我不会在TB内调用A的成员函数的,A对象也不会出现在TB内,A的成员函数都是一些任务函数,是不会以成员函数的形式调用的,是以类似回调函数的机制来调用
dbzhang800 2011-08-13
  • 打赏
  • 举报
回复
基本概念错了。
假定你有两个线程 TA 和 TB,
TA、TB 内分别创建了对象 A、B

然后你在TB内调用A的成员函数,就是调用一个普通函数而已,此时和线程TA没什么关系,代码在TB内执行。

如果

16,813

社区成员

发帖
与我相关
我的任务
社区描述
Qt 是一个跨平台应用程序框架。通过使用 Qt,您可以一次性开发应用程序和用户界面,然后将其部署到多个桌面和嵌入式操作系统,而无需重复编写源代码。
社区管理员
  • Qt
  • 亭台六七座
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧