QThread 继承 QObject 。它发射指示线程启动 (或执行完成) 的信号,且还提供了几个槽。
更有趣的是 QObject 可以用于多线程,发射援引其它线程槽的信号,并把事件张贴给 "存活" 于其它线程中的对象。这是可能的,因为每个线程都允许拥有它自己的事件循环。
QObject 可重入。它的大多数非 GUI (图形用户界面) 子类,譬如 QTimer , QTcpSocket , QUdpSocket and QProcess ,也可重入,使之可能从多线程同时使用这些类。注意,设计是从单线程创建和使用这些类;在某个线程中创建对象并从另一线程调用其函数,不能保证能工作。要注意存在 3 个约束:
this
) 作为在线程中创建对象的父级 (由于
QThread
对象自身是在另一线程中创建的)。
尽管 QObject 是可重入 GUI 类,显而易见 QWidget 及其所有子类,都不可重入。只可以从主线程使用它们。如前所述, QCoreApplication::exec () 还必须从该线程调用。
在实践中,不可能在主线程外的其它线程中使用 GUI (图形用户界面) 类,通过把耗时操作放入单独工作者线程,并在工作线程完成时在主线程屏幕中显示结果,可轻松解决。此实现方式可以用于 Mandelbrot 范例和 阻塞 Fortune 客户端范例 .
一般而言,创建 QObject 先于 QApplication 不支持,且退出时可能导致奇怪崩溃,从属平台。这意味着静态实例 QObject 也不支持。结构合理的单 (或多) 线程应用程序应该使 QApplication 被首先创造,且最后销毁 QObject .
每个线程都可以拥有它自己的事件循环。初始线程启动其事件循环是使用 QCoreApplication::exec (),或对于单对话框 GUI (图形用户界面) 应用程序,有时是 QDialog::exec ()。其它线程启动事件循环可以使用 QThread::exec ()。像 QCoreApplication , QThread 提供 exit (int) 函数和 quit () 槽。
线程中的事件循环使之可能为要使用某些非 GUI Qt 类的线程,要求存在事件循环 (譬如 QTimer , QTcpSocket ,和 QProcess )。还使之可能把来自任何线程的信号,连接到特定线程槽。阐述这的更多细节在 信号和槽跨线程 以下章节。
A QObject 实例据称是 live 在创建它的线程中。此对象的事件由该线程的事件循环分派。线程对于 QObject 存活的获得是使用 QObject::thread ().
The QObject::moveToThread () 函数改变对象,及其子级的线程亲缘关系 (对象无法移动,若它拥有父级)。
调用
delete
在
QObject
从线程而不是某个线程其
owns
对象 (或以其它方式访问对象) 是不安全的,除非保证对象在那刻不处理事件。使用
QObject::deleteLater
() 代替,和
DeferredDelete
事件将被张贴,最终将拾取对象线程的事件循环。默认情况下,线程
owns
a
QObject
是线程
creates
the
QObject
,但不后于
QObject::moveToThread
() 被调用。
若没有事件循环在运行,就不会将事件交付给对象。例如,若创建 QTimer 对象在线程,但从不调用 exec (), QTimer 将从不发射其 timeout () 信号。调用 deleteLater () 不会工作 (这些限定也应用于主线程)。
可以在任何时间手动将事件张贴给任何线程中的任何对象,使用线程安全函数 QCoreApplication::postEvent ()。将通过创建对象线程的事件循环,自动分派事件。
支持事件过滤器的所有线程,具有监视对象必须活在如被监视对象的同一线程中的限定。同样, QCoreApplication::sendEvent () (不像 postEvent ()) can only be used to dispatch events to objects living in the thread from which the function is called.
QObject 及其所有子类都不是线程安全的。这包括整个事件交付系统。它很重要,记住事件循环可能把事件交付给 QObject 子类,当从另一线程访问对象时。
若正调用函数在 QObject 子类未活在当前线程中且对象可能接收事件,就必须保护所有访问对 QObject 子类的内部数据按互斥;否则,可能经历崩溃 (或其它不期望行为)。
像其它对象, QThread objects live in the thread where the object was created – not 在创建线程中,当 QThread::run () 被调用。提供槽通常不安全在 QThread 子类,除非采用互斥保护成员变量。
另一方面,可以安全地发射信号从 QThread::run () 实现,因为信号发出是线程安全的。
Qt 支持这些信号/槽连接类型:
注意: 使用这种类型连接同一线程中的对象,会导致死锁。
false
.
可以指定连接类型,通过把额外自变量传递给 connect (). Be aware that using direct connections when the sender and receiver live in different threads is unsafe if an event loop is running in the receiver's thread, for the same reason that calling any function on an object living in another thread is unsafe.
QObject::connect () 本身是线程安全的。
The Mandelbrot example uses a queued connection to communicate between a worker thread and the main thread. To avoid freezing the main thread's event loop (and, as a consequence, the application's user interface), all the Mandelbrot fractal computation is done in a separate worker thread. The thread emits a signal when it is done rendering the fractal.
同样, 阻塞 Fortune 客户端范例 使用单独线程与 TCP 服务器进行异步通信。