Qt多线程编程中子线程如何调用主线程中的成员变量?

论坛 期权论坛 期权     
匿名的论坛用户   2021-1-7 19:05   9517   2
最近要编写一个多线程程序,以前用MFC感觉还挺方便,可以在主窗口类中声明一个静态线程函数,后面直接开始线程,并且在次线程的实现函数中通过LPVOID lpParam就可以实现将主线程类中的成员变量传递给次线程。
现在我用Qt,想在次线程中调用主线程(主线程是由QDialog继承过来的)类中的成员变量,却怎么也不成功,到底应该如何实现主线程与次线程的变量共享呀,如果都要用信号和槽,那岂不是太麻烦;我试过在主线程中将要在次线程中用到的成员变量声明为static静态变量,不过还是没有成功。
分享到 :
0 人收藏

2 个回复

倒序浏览
2#
热心的小回应  16级独孤 | 2021-1-7 19:05:40
如果是写操作,请用信号槽。不用信号槽的话,需要加锁,会影响性能。
子线程中对象emit信号。主线程中对象捕获后执行相关操作。

如果是单纯的读操作,很简单啊,你只要持有目标对象指针,目标对象写个type getXXX() const;方法,直接调用就ok了,和跨不跨线程没任何关系。

另外,请勿跨线程控制QWidget及其子对象,Qt不允许在非主线程控制GUI。
准确的说,QWidget, QTimer, QTjread, QIODevice对象,都有部分api不允许跨线程操作,否则会执行失败,控制台会有错误日志。

跨线程操作对象,这其实是个很朴素的所有权概念,只不过是逻辑意义上的所有权。
可以参照智能指针的内存所有权概念来类比,那个是实际意义上的所有权。
跨所有权的操作,只有一步到位的读操作是安全的,iterator这种多步执行的都可能遇到迭代器失效。而写操作是不安全的,必须通过加锁等代价很高的方式来进行。

因此,所有权是最重要的安全线越过了这条线,没人能保证你的安全,你只能付出极高的代价来实现,而且从逻辑层面上就是不合法的,严重破坏了封装性,提高了耦合度。

最优解,是退到安全线后,也就是用异步操作来实现所有写操作,如Qt的信号槽。只有在有极端实时需求时,才考虑直接越过安全线的暴力同步操作。

========================
========以下内容毁三观========
========================

然而,同步操作依旧保证不了实时性!
然而,同步操作依旧保证不了实时性!
然而,同步操作依旧保证不了实时性!

跨线程的同步写操作,必须加锁。加锁就会存在竞争,就会存在阻塞,该发生延迟的一样发生延迟。
如果你通过优化架构逻辑和代码算法,让两者尽可能不发生竞争了呢?
那异步同样没延迟了!

异步操作是如何实现的?
无非是把你的请求推送到对方线程的事件队列排队执行。这个也是跨线程写,只不过用了比如原子操作来实现了一个无锁队列。

当有竞争时,同步操作要阻塞等待,异步操作要队列等待,本质相同。
当没有竞争时,同步操作直接完成,异步操作入队后直接就出队了也是直接完成,没啥区别。

当然,同步操作里,发起方和执行方都在同一线程,不用担心对方会因线程调度无法实时响应。
然而发起方你自己也是线程,你自己也会被调度走的!在你加锁等待时,对方的线程也可能被调度走了导致你在空转的!


因此,只有在和系统,和硬件打交道时,由驱动层,由内核态发起中断或者回调,这时同步操作才有意义,因为可以保证发起者不会被调度走。
但依旧规避不了第二个问题——持有锁的目标线程被调度走后,你依旧只能在锁面前干等着。

所以,只要涉及到多线程,我不觉得同步操作的实时性有本质上的优势。

并且,只要不是做嵌入式,用户场合里99%代码都是全程在用户态执行。这时用同步操作,除了提高耦合,我不觉得有任何优势。

不然为毛js等语言纷纷要搞async/await,甚至连c++都在做提案了?
以前不是用回调写出了从操作系统到驱动程序到web应用的整个世界么?
原因还不是同步太违背工程学原理了么。

同步操作,归根结底是为了解决一种反人类的写法的——目标线程用while(true)处理任务,我要插队进去只能强行同步调用。
然而在异步编程里,即使是常驻操作也不会是while(true)。全都可以用事件系统进行事件响应。
比如网络服务端,不需要while检查请求,只需要监听socket的连接请求,接收请求就行了。
在处理请求时,同步模型里是加上锁的,无法响应同步调用。异步模型是线程在忙,调用事件排队等待。
在没处理请求时,同步模型可以直接拿到锁开始操作。异步模型下事件队列为空,来了新指令也能直接响应。
如果没外部请求,也没调用操作时,同步模型还得while(true)空转,异步模型线程直接停了,来事件时才会唤醒,岂不美哉?

所以,同步操作的那把锁,只不过是心理安慰,罢了。
3#
热心的小回应  16级独孤 | 2021-1-7 19:05:41
CPP又不是默认tls,只要变量在函数的作用域中,都可以调用…只是跨线程注意下线程安全…
话说,你用mfc可以用void *把参数传进去,qt就不行了?
个人建议,你还是先别纠结什么qt,mfc了,补补cpp和线程的基础吧…
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:3118703
帖子:623848
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP