QThread inherits QObject. It emits signals to indicate that the thread started or finished executing, and provides a few slots as well.
I wanted to cite this mailing list question from me about models and views on different threads in Qt (along with the ensuing answers). The qt-interest mailing list entries from 2009 seem to have all but disappeared from the web, but I found this one in an Internet Archive cache off of 'gmane'. Thread Support in Qt. Qt provides thread support in the form of basic platform-independent threading classes, a thread-safe way of posting events, and a global Qt library lock that allows you to call Qt methods from different threads. This document is intended for an audience that has knowledge and experience with multithreaded applications.
More interesting is that QObjects can be used in multiple threads, emit signals that invoke slots in other threads, and post events to objects that 'live' in other threads. This is possible because each thread is allowed to have its own event loop.
QObject Reentrancy
QObject is reentrant. Most of its non-GUI subclasses, such as QTimer, QTcpSocket, QUdpSocket and QProcess, are also reentrant, making it possible to use these classes from multiple threads simultaneously. Note that these classes are designed to be created and used from within a single thread; creating an object in one thread and calling its functions from another thread is not guaranteed to work. There are three constraints to be aware of:
- The child of a QObject must always be created in the thread where the parent was created. This implies, among other things, that you should never pass the QThread object (
this
) as the parent of an object created in the thread (since the QThread object itself was created in another thread). - Event driven objects may only be used in a single thread. Specifically, this applies to the timer mechanism and the network module. For example, you cannot start a timer or connect a socket in a thread that is not the object's thread.
- You must ensure that all objects created in a thread are deleted before you delete the QThread. This can be done easily by creating the objects on the stack in your run() implementation.
Although QObject is reentrant, the GUI classes, notably QWidget and all its subclasses, are not reentrant. They can only be used from the main thread. As noted earlier, QCoreApplication::exec() must also be called from that thread.
In practice, the impossibility of using GUI classes in other threads than the main thread can easily be worked around by putting time-consuming operations in a separate worker thread and displaying the results on screen in the main thread when the worker thread is finished. This is the approach used for implementing the Mandelbrot Example and the Blocking Fortune Client Example.
In general, creating QObjects before the QApplication is not supported and can lead to weird crashes on exit, depending on the platform. This means static instances of QObject are also not supported. A properly structured single or multi-threaded application should make the QApplication be the first created, and last destroyed QObject.
Per-Thread Event Loop
Each thread can have its own event loop. The initial thread starts its event loop using QCoreApplication::exec(), or for single-dialog GUI applications, sometimes QDialog::exec(). Other threads can start an event loop using QThread::exec(). Like QCoreApplication, QThread provides an exit(int) function and a quit() slot.
An event loop in a thread makes it possible for the thread to use certain non-GUI Qt classes that require the presence of an event loop (such as QTimer, QTcpSocket, and QProcess). It also makes it possible to connect signals from any threads to slots of a specific thread. This is explained in more detail in the Signals and Slots Across Threads section below.
A QObject instance is said to live in the thread in which it is created. Events to that object are dispatched by that thread's event loop. The thread in which a QObject lives is available using QObject::thread().
The QObject::moveToThread() function changes the thread affinity for an object and its children (the object cannot be moved if it has a parent).
Calling delete
on a QObject from a thread other than the one that owns the object (or accessing the object in other ways) is unsafe, unless you guarantee that the object isn't processing events at that moment. Use QObject::deleteLater() instead, and a DeferredDelete event will be posted, which the event loop of the object's thread will eventually pick up. By default, the thread that owns a QObject is the thread that creates the QObject, but not after QObject::moveToThread() has been called.
If no event loop is running, events won't be delivered to the object. For example, if you create a QTimer object in a thread but never call exec(), the QTimer will never emit its timeout() signal. Calling deleteLater() won't work either. (These restrictions apply to the main thread as well.)
You can manually post events to any object in any thread at any time using the thread-safe function QCoreApplication::postEvent(). The events will automatically be dispatched by the event loop of the thread where the object was created.
Event filters are supported in all threads, with the restriction that the monitoring object must live in the same thread as the monitored object. Similarly, QCoreApplication::sendEvent() (unlike postEvent()) can only be used to dispatch events to objects living in the thread from which the function is called.
Accessing QObject Subclasses from Other Threads
QObject and all of its subclasses are not thread-safe. This includes the entire event delivery system. It is important to keep in mind that the event loop may be delivering events to your QObject subclass while you are accessing the object from another thread.
If you are calling a function on an QObject subclass that doesn't live in the current thread and the object might receive events, you must protect all access to your QObject subclass's internal data with a mutex; otherwise, you may experience crashes or other undesired behavior.
Like other objects, QThread objects live in the thread where the object was created -- not in the thread that is created when QThread::run() is called. It is generally unsafe to provide slots in your QThread subclass, unless you protect the member variables with a mutex.
On the other hand, you can safely emit signals from your QThread::run() implementation, because signal emission is thread-safe.
Signals and Slots Across Threads
Qt supports these signal-slot connection types:
- Auto Connection (default) If the signal is emitted in the thread which the receiving object has affinity then the behavior is the same as the Direct Connection. Otherwise, the behavior is the same as the Queued Connection.'
- Direct Connection The slot is invoked immediately, when the signal is emitted. The slot is executed in the emitter's thread, which is not necessarily the receiver's thread.
- Queued Connection The slot is invoked when control returns to the event loop of the receiver's thread. The slot is executed in the receiver's thread.
- Blocking Queued Connection The slot is invoked as for the Queued Connection, except the current thread blocks until the slot returns.
Note: Using this type to connect objects in the same thread will cause deadlock.
- Unique Connection The behavior is the same as the Auto Connection, but the connection is made only if it does not duplicate an existing connection. i.e., if the same signal is already connected to the same slot for the same pair of objects, then the connection is not made and connect() returns
false
.
The connection type can be specified by passing an additional argument to 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() itself is thread-safe.
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.
Qt Execute Slot In Another Thread Size
Similarly, the Blocking Fortune Client Example uses a separate thread for communicating with a TCP server asynchronously.
© 2020 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.
Home All Classes Main Classes Annotated Grouped Classes Functions |
Qt provides thread support in the form of basic platform-independentthreading classes, a thread-safe way of posting events, and a globalQt library lock that allows you to call Qt methods from differentthreads.
This document is intended for an audience that has knowledge andexperience with multithreaded applications. Recommended reading:
Enabling Thread Support
When Qt is installed on Windows, thread support is an option on somecompilers.
On Mac OS X and Unix, thread support is enabled by adding the-thread option when running the configure script. On Unixplatforms where multithreaded programs must be linked in special ways,such as with a special libc, installation will create a separatelibrary, libqt-mt and hence threaded programs must be linkedagainst this library (with -lqt-mt) rather than the standard Qtlibrary.
On both platforms, you should compile with the macro QT_THREAD_SUPPORT defined (e.g. compile with-DQT_THREAD_SUPPORT). On Windows, this is usually done by anentry in qconfig.h.
The Thread Classes
These classes are built into the Qt library when thread support is enabled:
- QThread - Provides the means to start a new thread, which beginsexecution in your reimplementation of QThread::run(). This is similarto the Java thread class.
- QMutex - Provides a mutual exclusion lock (also know as a mutex).
- QMutexLocker - A convenience class which automatically locks andunlocks a QMutex. QMutexLocker is useful in complicated code, or incode which uses exceptions. See the documentation for more details.
- QWaitCondition - Provides a way for threads to go to sleep untilwoken up by another thread.
- QSemaphore - Provides a simple integer semaphore.
Important Information
When using Qt in a multithreaded program, it is important tounderstand the definition of the terms reentrant and thread-safe:
- reentrant - Describes a function which can be calledsimultaneously by multiple threads when each invocation of thefunction references unique data. Calling a reentrant functionsimultaneously with the same data is not safe, and such invocationsshould be serialized.
- thread-safe - Describes a function which can be calledsimultaneously by multiple threads when each invocation referencesshared data. Calling a thread-safe function simultaneously with thesame data is safe, since all access to the shared data are serialized.
Most C++ member functions are inherently reentrant, since they onlyreference class member data. Any thread can call such a memberfunction on an instance, as long as no other thread is calling amember function on the same instance. For example, given the class Number below:
The methods Number::number() and Number::setNumber() arereentrant, since they only reference unique data. Only one thread ata time can call member functions on each instance of Number.However, multiple threads can call member functions on separateinstances of Number.
Thread-safe functions usually use a mutex (e.g a QMutex) to serializeaccess to shared data. Because of this, thread-safe functions areusually slower than reentrant functions, because of the extra overheadof locking and unlocking the mutex. For example, given the class Counter below:
Since the modifications of the static instances integer are notserialized, this class is not thread-safe. So make it threadsafe, amutex must be used:
Thread-safe Event Posting
In Qt, one thread is always the GUI or event thread. This is thethread that creates a QApplication object and callsQApplication::exec(). This is also the initial thread that callsmain() at program start. This thread is the only thread that isallowed to perform GUI operations, including generating and receivingevents from the window system. Qt does not support creatingQApplication and running the event loop (with QApplication::exec()) ina secondary thread. You must create the QApplication object and callQApplication::exec() from the main() function in your program.
Threads that wish to display data in a widget cannot modify the widgetdirectly, so they must post an event to the widget usingQApplication::postEvent(). The event will be delivered later on bythe GUI thread.
Qt Execute Slot In Another Thread Set
Normally, the programmer would like to include some information in theevent sent to the widget. See the documentation for QCustomEvent formore information on user-defined events.
Threads and QObject
The QObject class itself is reentrant. However, certain rulesapply when creating and using QObjects in a thread that is not the GUIthread.
- None of the QObject based classes included in the Qt library arereentrant. This includes all widgets (e.g. QWidget andsubclasses), OS kernel classes (e.g. QProcess, QAccel, QTimer), andall networking classes (e.g. QSocket, QDns).
- QObject and all of its subclasses are notthread-safe. Thisincludes the entire event delivery system. It is important toremember that the GUI thread may be delivering events to your QObjectsubclass while you are accessing the object from another thread. Ifyou are using QObject in a thread that is not the GUI thread, and youare handling events sent to this object, you must protect allaccess to your data with a mutex; otherwise you may experience crashesor other undesired behavior.
- As a corollary to the above, deleting a QObject while pendingevents are waiting to be delivered can cause a crash. You must notdelete the QObject directly from a thread that is not the GUI thread.Use the QObject::deleteLater() method instead, which will cause theevent loop to delete the object after all pending events have beendelivered to the object.
The Qt Library Mutex
QApplication includes a mutex that is used to protect access to windowsystem functions. This mutex is locked while the event loop isrunning (e.g. during event delivery) and unlocked when the eventloopgoes to sleep. Note: The Qt event loop is recursive, and the librarymutex is not unlocked when re-entering the event loop (e.g. whenexecuting a modal dialog with QDialog::exec()).
If another thread locks the Qt library mutex, then the event loop willstop processing events, and the locking thread may do simple GUIoperations. Operations such as creating a QPainter and drawing a lineare examples of simple GUI operations:
Any operations that generate events must not be called by any threadother than the GUI thread. Examples of such operations are:
- creating a QWidget, QTimer, QSocketNotifier, QSocket or other network class.
- moving, resizing, showing or hiding a QWidget.
- starting or stoping a QTimer.
- enabling or disabling a QSocketNotifier.
- using a QSocket or other network class.
Events generated by these operations will be lost on some platforms.
Threads and Signals and Slots
The Signals and Slots mechanism can be used in separate threads, aslong as the rules for QObject based classes are followed. The Signalsand Slots mechanism is synchronous: when a signal is emitted, allslots are called immediately. The slots are executed in the threadcontext that emitted the signal.
Warning: Slots that generate window system events or use window systemfunctions mustnot be connected to a signal that is emitted froma thread that is not the GUI thread. See the Qt Library Mutex sectionabove for more details.
Threads and Shared Data
Qt provides many implicitly shared and explicitly shared classes. Ina multithreaded program, multiple instances of a shared class canreference shared data, which is dangerous if one or more threadsattempt to modify the data. Qt provides the QDeepCopy class, whichensures that shared classes reference unique data. See thedocumentation for more details.
Threads and the SQL Module
The classes in the SQL Module can be used in separate threads, as longas the rules for QObject based classes are followed.
The 3rd party libraries used by the QSqlDrivers can impose otherrestrictions on using the SQL Module in a multithreaded program. Forexample, the PostgreSQL library requires a separate connection perthread. Consult the documentation for your 3rd party library for moreinformation.
Caveats
Some things to watch out for when programming with threads:
- As mentioned above, QObject based classes are neither thread-safenor reentrant. This includes all widgets (e.g. QWidget andsubclasses), OS kernel classes (e.g. QProcess, QAccel), and allnetworking classes (e.g. QSocket, QDns).
- Deleting a QObject while pending events are waiting to be deliveredwill cause a crash. If you are creating QObjects in a thread that isnot the GUI thread and posting events to these objects, you should notdelete the QObject directly. Use the QObject::deleteLater() methodinstead, which will cause the event loop to delete the object afterall pending events have been delivered to the object.
- Don't do any blocking operations while holding the Qt librarymutex. This will freeze up the event loop.
- Make sure you unlock a recursive QMutex as many times as you lockit, no more and no less.
- Don't mix the normal Qt library and the threaded Qt library in yourapplication. This means that if your application uses the threaded Qtlibrary, you should not link with the normal Qt library, dynamicallyload the normal Qt library or dynamically load another library orplugin that depends on the normal Qt library. On some systems, doingthis can corrupt the static data used in the Qt library.
- Qt does not support creating QApplication and running the eventloop (with QApplication::exec()) in a secondary thread. You mustcreate the QApplication object and call QApplication::exec() from themain() function in your program.
Copyright © 2003Trolltech | Trademarks |