Posted  by  admin

Qt Slot Thread-safety

Meeting C++

Signals and slots were one of the distinguishing features that made Qt an exciting and innovative tool back in time. But sometimes you can teach new tricks to an old dog, and QObjects gained a new way to connect between signals and slots in Qt5, plus some extra features to connect to other functions which are not slots. Qt Slot Thread Safety information regarding identity during the registration process. Any false information or impersonation of any person or entity, misrepresentation regarding any affiliation with another person, entity or association, use of false headers or other acts or omissions to conceal one’s identity from LV BET for any purpose will. C: Thread Safety in a Signal/Slot Library. I suspect there is no clearly good answer, but clarity will come from documenting the guarantees you wish to make about concurrent access to an Emitter object. In this case if you emit a signal from one thread, and catching it in another one (e.g. In main GUI thread) - Qt will put a slot's call to the message queue and will make all calls sequentially. Read this for further info - http://qt-project.org/doc/qt-4.8/threads-qobject.html#signals-and-slots-across-threads.

published at 20.08.2015 15:28 by Jens Weller

This is the 7th blog post in my series about writing applications with C++ using Qt and boost. This time it is about how to notify one part of our application that something has happened somewhere else. I will start with Qt, as it brings with signals and slots a mechanism to do exactly that. But, as I have the goal not to use Qt mainly in the UI Layer, I will also look on how to notify other parts of the application, when things are changing. The last episode was about QWidgets and data.

The video for this episode:

Signals and Events in Qt

But lets start with Qt. Qt offers two different systems for our needs, Qt signal/slot and QEvents. While Qt signal/slot is the moc driven signaling system of Qt (which you can connect to via QObject::connect), there is a second Event interface informing you about certain system-like events, such as QMouseEvent, QKeyEvent or QFocusEvent. Usually you have to overwrite a method to receive such events, or use an event filter, like I showed in my last post for QFocusEvents. Some classes translate QEvents to signals, such as the TreeView, which has a signal for displaying context menus. But as this blog post is more on signaling then system events...

Qt has had its own signaling mechanism for a long time now, so when you use Qt, you also will use QSignals. Qt also uses its own keywords for this: signals, slots and emit. There is an option to turn this of, and use the macros Q_SIGNAL/S,Q_SLOT/S and Q_EMIT instead: CONFIG += no_keywords. This allows to use 3rd party libraries which use these terms, e.g. boost::signal. Qt signal/slot implementation is thread safe, so that you can use it to send messages between different QThreads, this is especially important, as anything UI related should run in the main thread of Qt, anything that could block your UI should not run in this thread, so running jobs in a QThreadPool and emitting the finished result as a signal is a common pattern. Maybe I will touch this in a later post...

Qt Slot Thread-safety

For now, lets see the basics of using signals and slots in Qt. This is the code from my MainWindow class constructor, connecting several signals to slots:

So, the traditional, moc driven connect method is QObject* derived sender, the SIGNAL macro defining the signal to connect to, followed by the QObject* derived receiver, then SLOT(...) is the last argument, naming the slot to connect to. There is a fifth defaultet parameter: the ConnectionType. The last line contains the new, lambda based connection option, where you again have the sender and its slot, this time as a method-pointer, and then followed by a lambda acting as the receiving slot.

Slot

This syntax can lead to a rare error, when ever a signal is overloaded, like QComboBox::currentIndexChanged, which is available with an int or QString parameter. Then you'll need an ugly static_cast to tell the compiler which version you'd like:

In this case I didn't even needed the argument from the slot. It is fairly easy to use your own signals and slots, all you need is a QObject derived class, which is processed by the moc. Mostly of course you already have classes derived from QObject indirectly, which then use signals and slots, like the page panel class:

So, slots and signals are normal member functions, declared after the qt-specific keyword signals/slots. When you want to emit a signal, its enough to just write 'emit my_signal();', and all observers on this signal will get notified. Slots are often used to react to certain events in the UI, like the currentIndexChanged signal in this case. In the widget editor of QtCreator you get an overview of available signals when right clicking and selecting 'go to slot...', this will create a slot for this signal in your QWidget derived class.

There is also the option to map certain widgets to certain values when a signal fires, this is done via QSignalMapper. I use this in a different program to have one widget for editing flag like settings, where each flag is a bit in a settings value:

The constructor only takes a QStringList for the option names, and an int for how many columns of check boxes the current use case should have. The QSignalMapper is a member variable, and each QCheckBox connects its clicked signal to the map() slot of QSignalMapper. With setMapping the connection between the sender and the value is set up. QSignalMapper offers int, QObject*, QWidget* and QString as mapping values. QVariant or a generic interface is not provided by Qt. In the clicked slot I simply toggle the bit for the corresponding flag.

When working in Qt, most of it types provide support for signals and slots through deriving from QObject, which offers connect/disconnect methods to manage your slot connections. This brings again the disadvantages of QObject and the moc, as templates can't be used in this context, all classes using signal/slot must be concrete classes. Deriving your classes from templates (CRTP e.g.) can help here to mix in a generic layer.

While Qt is fairly well prepared to manage its own messaging needs, what alternatives exist, that could be used in the non Qt related code? The C++ standard offers currently only std::function, which can be used to implement a callback mechanism. But this has its limitations, of a 1:1 or 1:many connection this is a viable option. I use it to notify my MainWindow class that a node in the tree has changed its name. Also its useful to implement classes which execute a callback in a certain context, like EventFilter in the last blog post in this series. But std::function is not an implementation of the observer pattern, and implementing your own with it would be reinventing the wheel. Boost has had for a long time a signal library, which now is available as version 2: boost::signals2.

Using boost::signals2

Honestly, if I could avoid using signals2, I would, as it has one certain disadvantage: build times increase. So far my project is kind of small, has only a few classes, which most of are less then 100 loc. Adding boost::signals2 to a class makes it hard to build a project quickly for debugging or just seeing if the work of the past hour still compiles.

The need for signals2 came in my application, when I began to understand, that there are some events, which go from the Qt layer into the boost/standard C++ layer, and then need to travel back into the Qt layer. Each Page has a shared_ptr to a layout object, which is part of a LayoutItem holding the list of layouts for a document. There is one LayoutPanel to edit, create and delete layouts in LayoutItem, and each PagePanel has a QComboBox, so that the user can select the layout for the page. Now, when a user creates/renames a layout, each PagePanel needs to be notified, but when it gets deleted, also page needs to change. This could be implemented in the Qt layer, each Qt class involved has access to the boost/C++ layer, and can make the necessary changes. But then, this important business logic of removing a layout will only work through the UI. When I use boost::signals2, it can be done in the boost/standard C++ layer.

boost::signals2 has a signal template, which has the signature as the argument, this signal type also then has the typedef for the slot type, signal::connect returns a connection object:

When ever an object subscribes to the layout signals, it must to so for all three, the vector should invoke RVO. Currently, PagePanel is the only subscriber, it simply connects to the signals using boost::bind:

One detail here is, that I do use scoped_connection, which will call disconnect() on its destruction, while the default boost::signals2::connection class does not. scoped_connection can be moved, but not copied. But once it is in the vector, it will stay there. Also, you should forward declare the connection classes, so that you don't have to include the boost/signals2.hpp headers, this prevents leaking into other sources.

But boost::signals2 can do far more. I have no use for code that depends on the order of slots called, but you can specify this with signal::contect(int group, slot):

In some context it is interesting to handle the return value of a signal, for this boost::signal2 offers a combiner, which is the second template parameter to signal: signal<float(float,float), aggregate_combiner<std::vector<float> > >. This combiner then also overwrites the return value of the signal, which is now std::vector instead of float. Another feature is that you can block a connection with shared_connection_block.

boost::signal2 is currently header only, thread safe and offers a few more customization points, for example you can change the mutex, but also the signature type, which currently is boost::function.

Alternatives to boost::signals2

If you know very well what you are doing, you could use boost::signal instead of its new version, signals2. This might improve your compile times, but boost::signals is not any more maintained. Also, while signals2 is header-only, signals is not. The thread safety is a key feature of signals2, which at some time sooner or later will come into play in your code base. I don't want to introduce a 3rd party library into my project just to have signaling/observer pattern, but you should know, that there are a few alternatives (I googled that too):

  • libsigslot
    • has open bugs from 2003 - 2011, memory leaks and other issues. But seems to do the job.
  • libsigc++
    • a standard C++ implementation, inspired by Qt, you (might) have to derive your objects from a base class. Virtual function calls are the base of this library it seems, at least for method slots, which the call has to be derived from sigc::trackable.
    • gtkmm and glibmm seem to use this for their signaling needs.
    • the 5 open bugs seem to be feature requests mostly (and nil is a keyword in Object-C, well...)
    • the library has been rewritten using modern C++ idioms (claims the site)
  • This codeproject article from 2005 gives some insights, but C++11 changes some of them I think.
  • slimsig
    • seems to be a header only alternative to boost::signals2
    • 2 open bugs, no change in one year
  • boost::synapse
    • this library is proposed for boost, but has not yet been reviewed.
    • I think it could be a more lightweight alternative to signals2
    • Currently its not threadsafe.

The only disadvantage of boost::signal2 is really its impact on compile and link time, which can be reduced through pimple and other isolation techniques, so that a recompilation is only triggered when really needed. One idea which came in my mind during this blog post is a std_signal2 header, which replaces the boost types (function, mutex etc.) with the corresponding std types. I'm not sure how this would work out, but boost::signals2 seems to be pretty well build to do this, a lot of template parameters have default values which then configure the library, and are hidden from the day to day usage.

Qt Thread Example

Join the Meeting C++ patreon community!
This and other posts on Meeting C++ are enabled by my supporters on patreon!

Copyright Meetingcpp GmbH 2020 ImprintPiwik Opt outPrivacy Policy

Home · All Classes · Main Classes · Grouped Classes · Modules · Functions

Qt provides thread support in the form of platform-independent threading classes, a thread-safe way of posting events, and signal-slot connections across threads. This makes it easy to develop portable multithreaded Qt 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.

Earlier versions of Qt offered an option to build the library without thread support. Since Qt 4.0, threads are always enabled.

This document is intended for an audience that has knowledge of, and experience with, multithreaded applications. If you are new to threading see our Recommended Reading list.

Topics:

The Threading Classes

Qt includes the following thread classes:

  • QThread provides the means to start a new thread.
  • QThreadStorage provides per-thread data storage.
  • QMutex provides a mutual exclusion lock, or mutex.
  • QMutexLocker is a convenience class that automatically locks and unlocks a QMutex.
  • QReadWriteLock provides a lock that allows simultaneous read access.
  • QReadLocker and QWriteLocker are convenience classes that automatically lock and unlock a QReadWriteLock.
  • QSemaphore provides an integer semaphore (a generalization of a mutex).
  • QWaitCondition provides a way for threads to go to sleep until woken up by another thread.

Creating a Thread

To create a thread, subclass QThread and reimplement its run() function. For example:

Thread-safety

Then, create an instance of the thread object and call QThread::start(). The code that appears in the run() reimplementation will then be executed in a separate thread. Creating threads is explained in more detail in the QThread documentation.

Note that QCoreApplication::exec() must always be called from the main thread (the thread that executes main()), not from a QThread. 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.

In addition, you must create the QApplication (or QCoreApplication) object before you can create a QThread.

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 already locked, the thread will be put to sleep until the thread that current 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.

Reentrancy and Thread-Safety

Throughout the Qt documentation, the terms reentrant and thread-safe are used to specify how a function can be used in multithreaded applications:

  • A reentrant function can be called simultaneously by multiple threads provided that each invocation of the function references unique data.
  • A thread-safe function can be called simultaneously by multiple threads when each invocation references shared data. All access to the shared data is serialized.

By extension, a class is said to be reentrant if any of its functions can be called simultaneously by multiple threads on different instances of the class, and thread-safe if it even works if the different threads operate on the same instance.

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 C++ classes are inherently reentrant, since they typically only reference member data. Any thread can call such a member function on an instance of the class, as long as no other thread is calling a member function on the same instance. For example, the Counter class below is reentrant:

The class isn't thread-safe, because if multiple threads try to modify the data member n, the result is undefined. This is because C++'s ++ and -- operators aren't necessarily atomic. Indeed, they usually expand to three machine instructions:

  1. Load the variable's value in a register.
  2. Increment or decrement the register's value.
  3. Store the register's value back into main memory.

If thread A and thread B load the variable's old value simultaneously, increment their register, and store it back, they end up overwriting each other, and the variable is incremented only once!

Clearly, the access must be serialized: Thread A must perform steps 1, 2, 3 without interruption (atomically) before thread B can perform the same steps; or vice versa. An easy way to make the class thread-safe is to protect all access to the data members with a QMutex:

The QMutexLocker class automatically locks the mutex in its constructor and unlocks it when the destructor is invoked, at the end of the function. Locking the mutex ensures that access from different threads will be serialized. The mutex data member is declared with the mutable qualifier because we need to lock and unlock the mutex in value(), which is a const function.

Most Qt 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 functions are thread-safe; these are mainly thread-related classes such as QMutex, or fundamental functions such as QCoreApplication::postEvent().

Threads and QObjects

QThread inherits QObject. It emits signals to indicate that the thread started or finished executing, and provides a few slots as well.

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, QHttp, QFtp, and QProcess, are also reentrant, making it possible to use these classes from multiple threads simultaneously. There are two 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).
  • 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 and the Blocking Fortune Client example.

Per-Thread Event Loop

Each thread can have its own event loop. The initial thread starts its event loops using QCoreApplication::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().

Note that for QObjects that are created before QApplication, QObject::thread() returns zero. This means that the main thread will only handle posted events for these objects; other event processing is not done at all for objects with no thread. Use the QObject::moveToThread() function to change 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 another thread than the thread where it is created (or accessing the object in other ways) is unsafe unless you can guarantee that the object isn't processing events at the same moment. Use QObject::deleteLater() instead; it will post a DeferredDelete event, which the event loop of the object's thread will eventually pick up.

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.

Qt Signal Thread

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 three types of signal-slot connections:

  • With direct connections, the slot gets called immediately when the signal is emitted. The slot is executed in the thread that emitted the signal (which is not necessarily the thread where the receiver object lives).
  • With queued connections, the slot is invoked when control returns to the event loop of the thread to which the object belongs. The slot is executed in the thread where the receiver object lives.
  • With auto connections (the default), the behavior is the same as with direct connections if the signal is emitted in the thread where the receiver lives; otherwise, the behavior is that of a queued connection.

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.

Similarly, the Blocking Fortune Client example uses a separate thread for communicating with a TCP server asynchronously.

Threads and Implicit Sharing

Qt Thread Signal Slot

Qt uses an optimization called implicit data sharing for many of its value class, notably QImage and QString. In many people's minds, implicit sharing and multithreading are incompatible concepts, because of the way the reference counting is typically done. One solution is to protect the internal reference counter with a mutex, but this is prohibitively slow. Earlier versions of Qt didn't provide a satisfactory solution to this problem.

Beginning with Qt 4, implicit shared classes can safely be copied across threads, like any other value classes. They are fully reentrant. The implicit sharing is really implicit. This is implemented using atomic reference counting operations, which are implemented in assembly language for the different platforms supported by Qt. Atomic reference counting is very fast, much faster than using a mutex.

This having been said, if you access the same object in multiple threads simultaneously (as opposed to copies of the same object), you still need a mutex to serialize the accesses, just like with any reentrant class.

To sum it up, implicitly shared classes in Qt 4 are really implicitly shared. Even in multithreaded applications, you can safely use them as if they were plain, non-shared, reentrant classes.

Threads and the SQL Module

Qt Start Thread

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

Qt Public Slots

Recommended Reading