Qt Slots Thread Safe

Thread
  • Free Spins: Available after deposit bonus is redeemed/lost, credited as Qt Signals And Slots Thread Safe £2 bonus.
  • Cross-thread signal-slot connections are implemented by dispatching a QMetaCallEvent to the target object. A QObject instance can be moved to a thread, where it will process its events, such as timer events or slot/method calls. To do work on a thread, first create your own worker class that derives from QObject. Then move it to the thread.

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. Let’s review how to get the most of that feature. This assumes you are already moderately familiar with signals and slots.

Qt provides the signals and slots framework which allows you to do just that and is thread-safe, allowing safe communication directly from running threads to your GUI frontend.

One simple thought about the basics

Qt Slots Thread Safe Code

I am not going to bore you with repeating basic knowledge you already have, but I want you to look at signals and slots from a certain angle, so it will be easier to understand the design of the feature I will cover next. What’s the purpose of signals and slots? It’s a way in which “one object” makes sure that when “something happened”, then “other object” “reacts to something happened”. As simple as that. That can be expressed in pseudocode like this:

Notice that the four phrases that are into quotes in the previous paragraph are the four arguments of the function call in the pseudocode. Notice also that one typical way to write the connect statement is aligning the arguments like this, because then the first column (first and third arguments) are object instances that answer “where?” and the second column (second and fourth arguments) are functions that answer “what?”.

In C++ instead of pseudocode, and using real life objects and classes, this would look like this in Qt4 or earlier:

That could be a typical statement from a “Hello World” tutorial, where a button is created and shown, and when it’s pressed the whole window closes and the application terminates.

Now to the main point that I want you to notice here. This has a very subtle advantage over a typical mechanism used in standard C or C++ 11 like callbacks with function pointers and lambda functions wrapped in std::function, and is subtle only because is so nice we often forget about it when we have used signals and slots for a while. If the sender object is destroyed, it obviously can not emit any signal because it is a member function of its class. But for the sender to call the receiver, it needs a pointer to it, and you as a user, don’t need to worry at all about the receiver being destroyed and becoming invalid (that is done automatically by the library), so you very rarely need to call QObject::disconnect.

So signals and slots are very safe by default, and in an automatic way.

The new versus the old way to use connect

The previous example shows one way that works across old versions of Qt published so far (Qt 1 to 5). Recently a blog post about porting a tutorial application from Qt 1 to Qt 5.11 has been published, and no porting was needed at all for signals, slots, or the connections! That doesn’t mean the feature is perfect, since a new way to make connections was added, keeping all the previous functionality.

The main problem with the example above is that (as you probably knew, or guessed from being all uppercase) is that SIGNAL and SLOT are macros, and what those macros do is convert to a string the argument passed. This is a problem because any typo in what gets passed to those means that the call to connect would fail and return false. So since Qt 5.0, a new overload to QObject::connect exists, and supports passing as second and fourth arguments a function pointer to specify which member function should be called. Ported to the new syntax, the above example is:

Now any typo in the name will produce a compile time error. If you misspelled “click” with “clik” in the first example, that would only fail printing a warning in the console when that function gets called. If you did that in some dialog of an application you would have to navigate to that dialog to confirm that it worked! And it would be even more annoying if you were connecting to some error handling, and is not that easy to trigger said error. But if you did the same typo in the last example, it would be a compile time error, which is clearly much better.

This example is usually said to be using the “new syntax”, and the previous example the “old syntax”. Just remember that the old is still valid, but the new is preferred in most situations.

Since this is an exciting new feature added to a new major version, which has received some extra polishing during the minor releases, many blog posts from other members of the Qt community have been published about it (for example covering implementation details or the issues that could arise when there are arguments involved). I won’t cover those topics again, and instead I will focus on the details that in my experience would be most beneficial for people to read on.

No need to declare members as slots anymore (or almost)

The new syntax allows to call not just a member function declared as slot in the header with public slots: (or with protected or private instead of public), but any kind of function (more on that in the next section). There is still one use case where you would want to declare functions as slots, and that is if you want to make that function usable by any feature that happens at run time. That could be QML, for example.

Connecting to anything callable

Now we can connect to any “callable”, which could be a free standing function, a lambda function or a member function of an object that doesn’t derive from QObject. That looks in code like the following:

But wait, where is that nice symmetry with 2 rows and two columns now?

When you connect to a lambda, there is a receiver object, the lambda itself, but there is no signature to specify since it’s the function call operator (the same would happen to a function object or “functor”, by the way). And when there is a free standing function there is a signature, but there is no instance, so the third and the fourth arguments of the first two calls are somewhat merged. Note that the arguments are still checked at compile time: the signal has no arguments, and the lambda has no arguments either. Both sender and receiver are in agreement.

The example using std::bind requires a bit more explanation if you are not familiar with it. In this case we have the two objects and the two function pointers, which is to be expected for what is wanted. We don’t often think about it like this, but we always need a pointer to call a member function (unless it is static). When it is not used, it is because this is implicit, and this->call() can be shortened to call(). So what std::bind does here is create a callable object that glues together the particular instance that we want with one member function. We could do the same with a lambda:

Note that std::bind is actually much more powerful, and can be very useful when the number of arguments differ. But we will leave that topic to another article.

One common use of the above pattern with std::bind is when you have a class implemented through a data pointer (private implementation or pimpl idiom). If you need a button or a timer to call a member function of the private class that is not going to be a QObject, you can write something like this:

Recovering symmetry, safety and convenience

With the previous examples that nice balance of the four arguments is gone. But we are missing something more important.

What would happen if the lambda of the previous examples would use an invalid pointer? In the very first C++ example we showed a button wanting to close the application. Imagine that the button required to close a dialog, or stop some network request, etc. If the object is destroyed because said dialog is already closed or the request finished long ago, we want to manage that automatically so we don’t use an invalid pointer.

An example. For some reason you show some widget and you need to do some last minute update after it has been shown. It needs to happen soon but not immediately, so you use a timer with a short timeout. And you write

That works, but has a subtle problem. It could be that the widget gets shown and immediately closed. The timer under the scenes doesn’t know that, and it will happily call you, and crash the application. If you made the timer connect to a slot of the widget, that won’t happen: as soon as the dialog goes away, the connection gets broken.

Since Qt 5.2 we can have the best of both worlds, and recover that nice warm feeling of having a well balanced connect statement with two objects and two functions. 🙂

In that Qt version an additional overload was added to QObject::connect, and now there is the possibility to pass as third argument a so called “context object”, and as fourth argument the same variety of callables shown previously. Then the context object serves the purpose of automatically breaking the connection when the context is destroyed. That warranties the problem mentioned is now gone. You can easily handle that there are no longer invalid captures on a lambda.

The previous example is almost as the previous:

Now it is as if the lambda were a slot in your class, because to the timer, the context of the connection is the same.

The only requirement is that said context object has to be a QObject. This is not usually a problem, since you can create and ad-hoc QObject instance and even do simple but useful tricks with it. For example, say that you want to run a lambda only on the first click:

This will delete the ad-hoc QObject guard on the first invocation, and the connection will be automatically broken. The object also has the button as a parent, so it won’t be leaked if the button is never clicked and goes away (it will be deleted as well). You can use any QObject as context object, but the most common case will be to shut down timers, processes, requests, or anything related to what your user interface is doing when some dialog, window or panel closes.

Tip: There are utility classes in Qt to handle the lifetime of QObjects automatically, like QScopedPointer and QObjectCleanupHandler. If you have some part of the application using Qt classes but no UI tightly related to that, you can surely find a way to leverage those as members of a class not based on QObject. It is often stated as a criticism to Qt, that you can’t put QObjects in containers or smart pointers. Often the alternatives do exist and can be as good, if not better (but admittedly this is a matter of taste).

Bonus point: thread safety by thread affinity

The above section is the main goal of this article. The context object can save you crashes, and having to manually disconnect. But there is one additional important use of it: making the signal be delivered in the thread that you prefer, so you can save from tedious and error prone locking.

Again, there is one killer feature of signals and slots that we often ignore because it happens automatically. When one QObject instance is the receiver of a signal, its thread affinity is checked, and by default the signal is delivered directly as a function call when is the same thread affinity of the sender. But if the thread affinity differs, it will be delivered posting an event to the object. The internals of Qt will convert that event to a function call that will happen in the next run of the event loop of the receiver, so it will be in the “normal” thread for that object, and you often can forget about locks entirely. The locks are inside Qt, because QCoreApplication::postEvent (the function used to add the event to the queue) is thread-safe. In case of need, you can force a direct call from different threads, or a queued call from the same thread. Check the fifth argument in the QObject::connect documentation (it’s an argument which defaults to Qt::AutoConection).

Let’s see it in a very typical example.

This shows a class that derives from QRunnable to reimplement the run() function, and that derives from QObject to provide the finished() signal. An instance is created after the user activates a button, and then we show some progress bar and run the task. But we want to notify the user when the task is done (show some message, hide some progress bar, etc.).

In the above example, the third argument (context object) might be forgotten, and the code will compile and run, but it would be a serious bug. It would mean that you would attempt to call into the UI thread from the thread where the task was run (which is a helper thread pool, not the UI thread). This is wrong, and in some cases Qt will nicely warn you that you are using some function from the wrong thread, but if you are not lucky, you will have a mysterious crash.

Wrap up

Hopefully now you’ve understood why that odd point was made in the introduction section. You don’t have to agree that it is aesthetically pleasing to write the arguments to connect in two rows and two columns, but if you understood the importance of using a context object as a rule of thumb, you probably will find your preferred way to remember if that third argument is needed when you write (or review other’s) code using connect.

Meeting C++

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 Slots Thread Safe

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.

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.

Qt Slots Thread Safety

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):

Qt Thread Pool

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

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

Qt Virtual Slot