Home · Examples 


Thread Support in Qt

A detailed discussion of thread handling in Qt Jambi. Qt Jambi provides a thread-safe way of posting events. This makes it easy to develop portable multithreaded Qt Jambi applications and take advantage of multiprocessor machines. Multithreaded programming is also a useful paradigm for performing time-consuming operations without freezing the user interface of an application.

An application can use the Java Thread class to create new threads. The synchronized and volatile keywords are used in the standard way to control access to objects in threads. However, QObjects (classes that inherit from QObject) can only be used in QThreads, and they can only be accessed from that thread. More on this in the Threads and QObjects section.

Qt Jambi also provides classes for thread handling, as an alternative to using synchronize and volatile. We discuss these briefly in the The Threading Classes section.

This document is intended for an audience that has knowledge of, and experience with multithreaded applications and Java thread handling.

Topics:

The Threading Classes

Qt includes the following thread classes:
The thread classes of Qt Jambi provides an alternative way to start and manage threads than using the Java thread handling, with its synchronized and volatile keywords.

Note that Qt Jambis's threading classes are implemented with native threading APIs; e.g., Win32 and pthreads. Therefore, they can be used with threads of the same native API.

Creating a Thread

You can create a thread by initializing a java.lang.Thread or QThread, and then call the start() method. For example:
    class MyJavaRunnable implements Runnable
    {
        @Override
        public void run()
        {
            // Do whatever
        }
    }
...
        MyJavaRunnable javaRunnable = new MyJavaRunnable();
        QThread runner = new QThread(javaRunnable);
        runner.start();
Qt Jambi also provides the
QThreadPool class, which allows starting threads by providing a QRunnable. To create a thread in this way, subclass QRunnable and reimplement its run() method. For example:
    class MyJambiRunnable extends QRunnable
    {
        @Override
        public void run()
        {
            // Do whatever
        }
    }
...
        MyJambiRunnable jambiRunnable = new MyJambiRunnable();
        QThreadPool.start(jambiRunnable);
Note that QCoreApplication::exec() must always be called from the main thread (the thread that executes main()), not from a another thread. In GUI applications, the main thread is also called the GUI thread because it's the only thread that is allowed to perform GUI-related operations.

Synchronizing Threads

The
QMutex, QReadWriteLock, QSemaphore, and QWaitCondition classes provide means to synchronize threads. While the main idea with threads is that they should be as concurrent as possible, there are points where threads must stop and wait for other threads. For example, if two threads try to access the same global variable simultaneously, the results are usually undefined.

QMutex provides a mutually exclusive lock, or mutex. At most one thread can hold the mutex at any time. If a thread tries to acquire the mutex while the mutex is already locked, the thread will be put to sleep until the thread that currently holds the mutex unlocks it. Mutexes are often used to protect accesses to shared data (i.e., data that can be accessed from multiple threads simultaneously). In the Reentrancy and Thread-Safety section below, we will use it to make a class thread-safe.

QReadWriteLock is similar to QMutex, except that it distinguishes between "read" and "write" access to shared data and allows multiple readers to access the data simultaneously. Using QReadWriteLock instead of QMutex when it is possible can make multithreaded programs more concurrent.

QSemaphore is a generalization of QMutex that protects a certain number of identical resources. In contrast, a mutex protects exactly one resource. The Semaphores example shows a typical application of semaphores: synchronizing access to a circular buffer between a producer and a consumer.

QWaitCondition allows a thread to wake up other threads when some condition has been met. One or many threads can block waiting for a QWaitCondition to set a condition with wakeOne() or wakeAll(). Use wakeOne() to wake one randomly selected event or wakeAll() to wake them all. The Wait Conditions example shows how to solve the producer-consumer problem using QWaitCondition instead of QSemaphore.

Note that Qt's synchronization classes rely on the use of properly aligned pointers. For instance, you cannot use packed classes with MSVC.

QtConcurrent

The QtConcurrent namespace provides high-level APIs that make it possible to write multi-threaded programs without using low-level threading primitives such as mutexes, read-write locks, wait conditions, or semaphores. Programs written with QtConcurrent automatically adjust the number of threads used according to the number of processor cores available. This means that applications written today will continue to scale when deployed on multi-core systems in the future.

QtConcurrent includes functional programming style APIs for parallel list processing, including a MapReduce and FilterReduce implementation for shared-memory (non-distributed) systems, and classes for managing asynchronous computations in GUI applications:

Qt Concurrent supports several STL-compatible container and iterator types, but works best with Qt containers that have random-access iterators, such as QList or QVector. The map and filter methods accept both containers and begin/end iterators.

Reentrancy and Thread-Safety

Throughout the Qt documentation, the terms reentrant and thread-safe are used to specify how a method can be used in multithreaded applications: By extension, a class is said to be reentrant if each and every one of its methods can be called simultaneously by multiple threads on different instances of the class. Similarly, the class is said to be thread-safe if the methods can be called by different threads on the same instance.

Classes in the documentation will be documented as thread-safe only if they are intended to be used by multiple threads.

Note that the terminology in this domain isn't entirely standardized. POSIX uses a somewhat different definition of reentrancy and thread-safety for its C APIs. When dealing with an object-oriented C++ class library such as Qt, the definitions must be adapted.

Most Qt Jambi classes are reentrant and not thread-safe, to avoid the overhead of repeatedly locking and unlocking a QMutex. For example, QString is reentrant, meaning that you can use it in different threads, but you can't access the same QString object from different threads simultaneously (unless you protect it with a mutex yourself). A few classes and methods are thread-safe; these are mainly thread-related classes such as QMutex, or fundamental methods such as QCoreApplication::postEvent().

Threads and QObjects

As mentioned previously, when a QObject is to be created in a thread, you need to use the QThread class. For all other Qt Jambi classes, java.lang.Thread can be used. QThread is started the same way as a java.lang.Thread.
        MyJavaRunnable javaRunnable = new MyJavaRunnable();
        QThread runner = new QThread(javaRunnable);
        runner.start();

QObject Reentrancy

QObject is reentrant. Most of its non-GUI subclasses, such as QTimer, QTcpSocket, QUdpSocket, QHttp, QFtp, 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 methods from another thread is not guaranteed to work. There are three constraints to be aware of: Note also that the GUI classes, notably QWidget and all its subclasses, can can only be used from the main thread (i.e., the thread where the QApplication object were initialized). 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.

Using Signals to Communicate Between QObjects in Separate Threads

The functionality for the Qt Jambi signal mechanism is implemented in QSignalEmitter, which does not inherit QObject. It is therefore possible to send signals between QObjects living in different threads. The way to do this is to implement a class consisting of the signals to be sendt, and then emit or connect to these signals from the threads. A small example follows:Error parsing snippet.

Per-Thread Event Loop

Each thread can have its own event loop. The initial thread starts its event loops using
QApplication.initialize(). Other threads can start an event loop by creating a QEventLoop instance:
    class EventLoopThread implements Runnable
    {
        @Iverride
        public void run()
        {
            QEventLoop loop = new QEventLoop();
            loop.exec();

            // Do whatever
            
            loop.exit();
        }
    }

Like the main event loop started with QApplication::initialize(), QEventLoop provides an exit() method 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().

Note that QObjects must be created after the QApplication is initialize(); if not, they will not be part of the main event loop. Use the QObject::moveToThread() method to change the thread affinity for an object and its children (the object cannot be moved if it has a parent).

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 method 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 method 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.

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.

Threads and the SQL Module

A connection can only be used from within the thread that created it. Moving connections between threads or creating queries from a different thread is not supported.

In addition, the third party libraries used by the QSqlDrivers can impose further restrictions on using the SQL Module in a multithreaded program. Consult the manual of your database client for more information

Painting in Threads

QPainter can be used to paint onto QImage, QPrinter, and QPicture paint devices. Painting onto QPixmaps and QWidgets is not supported. On Mac OS X the automatic progress dialog will not be displayed if you are printing from outside the GUI thread.

Any number of threads can paint at any given time, however only one thread at a time can paint on a given paint device. In other words, two threads can paint at the same time if each paints onto separate QImages, but the two threads cannot paint onto the same QImage at the same time.

Note that on X11 systems without FontConfig support, Qt cannot render text outside of the GUI thread. You can use the QFontDatabase::supportsThreadedFontRendering() method to detect whether or not font rendering can be used outside the GUI thread.

Threads and Rich Text Processing

The QTextDocument, QTextCursor, and all related classes are reentrant.

Note that a QTextDocument instance created in the GUI thread may contain QPixmap image resources. Use QTextDocument::clone() to create a copy of the document, and pass the copy to another thread for further processing (such as printing).

Threads and the SVG module

The QSvgGenerator and QSvgRenderer classes in the QtSvg module are reentrant.


Copyright © 2009 Nokia Corporation and/or its subsidiary(-ies) Trademarks
Qt Jambi 4.5.2_01