Qt多线程-Threads and QObjects

QObject Reentrancy

QObject是可重入的,它大多数非GUI的子类,像QTimer,QTcpSocket,QUdpSocket和QProcess也是可重入的,这使得能同时在多线程中使用这些类。注意这些类被设计成需要在一个线程中创建和使用,在一个线程中创建一个对象,然后在另一个线程中调用它的函数是不被保证能工作。需要知道以下三个约束:

  • QObject的子对象必须总是应该在它父对象创建的线程中创建。这意味着,除其他情况外,永远不要将QThread对象(This)作为在线程中创建的对象的父对象传递(因为QThread对象本身是在另一个线程中创建的)。
  • 事件驱动对象应该在单线程中使用,特别地,这适用于计时器和网络模块。类似地,你不能开启一个计时器或者连接一个socket在一个非这个对象线程的线程中
  • 你应该确保在你删除某一QThread前,所有创建在该线程的对象已经被delete。这可以通过在run()实现中的堆栈上创建对象轻松完成。

一般地,在QApplication之前创建QObject是不被支持的,这会导致在退出时奇怪的崩溃,这取决于平台。这意味着静态实例化QObject对象也是不支持的。一个正确的结构化单线程或多线程程序应该在第一时间初始化QApplication,以及最后销毁QObject

Per-Thread Event Loop

每个线程能够拥有自己的事件循环,初始线程开始它的事件循环使用QCoreApplication::exec(),或者对于单对话框GUI程序,有时是QDialog::exec()。其他线程启动事件循环使用QThread::exec(),和QCoreApplication,QThread提供一个exec(int)函数和一个quit() slot
线程中的事件循环使线程可以使用某些需要存在事件循环的非GUI Qt类(比如QTimer,QTcpSocket,QUdpSocket和QProcess),这也使得线程可以连接来自任何线程信号到指定的线程。
QObject实例被认为存活在创建它的线程中。事件通过线程的事件循环分发到对象中,QObject存活的线程可以使用QObject::thread()获取
QObject::moveToThread()函数能够改变它和它子对象的关联线程(如果对象有父对象,则该对象不能移动)
从拥有该对象的线程以外的线程调用QObject上的delete(或以其他方式访问该对象)是不安全的,除非你保证这个对象此时没有在处理事件。使用QObject::deleteLater()作为代替,然后DerferredDelete事件将被发送,对象线程的事件循环会最终处理该事件。默认地 ,拥有该对象的线程是创建该对象的线程,但在调用QObject::moveToThread()后则不是。
如果没有事件循环在运行,事件不会发送给对象。例如,如果你在线程中创建一个QTimer对象,但是从不调用exec(),这个QTimer将永远不会触发它的timeout()信号。调用deleteLater()也不会工作。这个约束在主线程中也同样有效)
你可以在任意线程任意事件使用线程安全函数QCoreApplication::postEvent()手动发送事件到任意对象。这些事件将会自动发送到创建这个对象的线程的事件循环中

QObject::moveToThread

void QObject::moveToThread(QThread *targetThread)

为该Object和它子对象改变关联线程。有父对象时,该Object不能改变线程。事件处理将继续在目标线程中处理。
为了移动Object到主线程,可以使用QApplication::instance获取当前应用的指针,然后使用QApplication::thread()获取应用运行的线程,示例

myObject->moveToThread(QApplication::instance()->thread());

如果targetThread为nullptr,所有该Object和其子对象的事件处理会停止,因为他们不再有关联到任何线程上。
注意该Object所有激活的timer将会重置,timer首先将在当前线程中停止,然后在目标线程重新启动,结果是,在线程间不断地移动一个对象,将无限滞后timer的事件
在关联线程被更改前,QEvent::ThreadChange事件被发送到这个对象,你可以处理这个事件进行一些特别的处理。注意目标线程不为空时,任何被发送到这个对象的新事件将会被目标线程处理,当目标线程为空时,该对象和其子对象不会进行事件处理,因为它们不再关联到任何线程中。

警告:这个函数不是线程安全的;当前线程必须与当前线程亲和性相同。另一方面,这个函数只能将一个对象从当前线程“推向”另一个线程,而不能将一个对象从任意线程中“拉到”当前线程。这个规则有一个例外,没有关联线程的对象,能够被“拉到”当前线程

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值