What is The Qt::ConnectionType for multithread programming?

Cengizhan Varlı
7 min readSep 22, 2023

--

As you know, The Qt signal-slot mechanism is a fundamental concept in the Qt framework. It provides a way for objects to communicate with each other in a loosely coupled manner. This mechanism allows you to define custom signals and slots, which can be connected together to enable communication between different parts of your application.

Before moving on to our main topic, let’s briefly look at the qt signal slot mechanism.

Here’s a informations of concepts of the Qt signal-slot mechanism;

  1. Signals: Signals are special member functions declared in a QObject-derived class. They represent events or occurrences within the object that other parts of the program might be interested in. When a signal is emitted, it notifies all connected slots.
  2. Slots: Slots are member functions declared in QObject-derived classes as well. These functions are the recipients of signals and are executed in response to a signal being emitted. Slots can have parameters that receive data from the emitting signal.
  3. Connect: You can connect a signal to a slot using the QObject::connect method or the more convenient QObject::connect syntax. This establishes a connection between a signal and a slot, so that when the signal is emitted, the connected slot is invoked.
  4. Emit: To trigger a signal and notify its connected slots, you use the emit keyword in the signal's emitting class. This typically happens when an event or condition occurs that the signal represents.

In order to use the signal-slot mechanism, the relevant objects must be derived from the QObject class or the Q_OBJECT macro must be added to the private region of these classes. Like this;

More information about the signal-slot concept can be investigated from other sources.

Let’s take a brief look at the connect function.

QObject::connect() function

QObject::connect() function is a fundamental function in the Qt framework used for connecting signals and slots in Qt-based applications. It's a mechanism for inter-object communication, allowing one object to emit a signal and another object to respond to that signal by executing a slot function. This mechanism is a key part of Qt's event-driven architecture and is used extensively in Qt applications to handle events and propagate changes in a clean and efficient way.

If you want, you can examine the connect function prototypes that are overloaded more than once in “qobject.h”.

Some of them are as follows;

static QMetaObject::Connection connect(const QObject *sender, const char *signal,
const QObject *receiver, const char *member, Qt::ConnectionType = Qt::AutoConnection);

static QMetaObject::Connection connect(const QObject *sender, const QMetaMethod &signal,
const QObject *receiver, const QMetaMethod &method,
Qt::ConnectionType type = Qt::AutoConnection);
inline QMetaObject::Connection connect(const QObject *sender, const char *signal,
const char *member, Qt::ConnectionType type = Qt::AutoConnection) const;

As seen above, there is a Qt::ConnectionType parameter and the default value is Qt::AutoConnection. So, unless you specify otherwise, your connection type will be Qt::AutoConnection.

Let’s examine the Qt::ConnectionType.

You can access the Qt::ConnectionType enum by ctrl+click.

Qt::ConnectionType

Yes, this is our main topic, Qt::ConnectionType enum.

Qt::ConnectionType

  1. Qt::AutoConnection : This is the default connection type. The behavior depends on whether the sender and receiver are in the same thread or not. If they are in the same thread, a direct connection is made (function call), and if they are in different threads, a queued connection is made (the signal is queued to be invoked in the receiver's thread event loop). This is the most common and versatile type.
  2. Qt::DirectConnection : A direct connection is established between the signal and slot, and the slot is invoked immediately when the signal is emitted, even if the sender and receiver are in different threads. This can be risky if not used carefully in multi-threaded applications, as it may lead to synchronization issues.
  3. Qt::QueuedConnection : A queued connection is established, meaning the signal is placed in an event queue and executed in the receiver's thread event loop. This is safe for inter-thread communication and is often used when a signal from one thread needs to be processed in another thread.
  4. Qt::BlockingQueuedConnection : Similar to Qt::QueuedConnection, but it blocks the emitting thread until the slot has finished executing in the receiving thread. This can be useful in some situations where you want to ensure that the slot is processed before continuing in the emitting thread.
  5. Qt::UniqueConnection : Ensures that multiple connections to the same signal and slot are merged into a single connection. This is useful when you want to prevent multiple connections for the same signal-slot pair.

If the signal-slot mechanism is wanted to be used in the same thread, the slot method is called as soon as the signal is emitted. It seems like it’s no different than calling a method normally. This is called Qt::DirectConnection and the slot method is called as an instant response to the signal. It is the simplest form of the signal-slot mechanism and one of the first connection mechanism that most people experience when they learn Qt’s signal-slot mechanism. This is the type of connection we created between our A and B classes by defining a new project.

Let’s assume that there are two different threads and that the signal-slot mechanism is established between these threads.

Let’s examine Qt::QueuedConnection as first.

Our “main.cpp” file is as follow;

main.cpp
  • std::unique_ptr<Thread_1> thread1(new Thread_1(“Thread 1”)) and std::unique_ptr<Thread_2> thread2(new Thread_2(“Thread 2”)) : These lines create two unique pointers to instances of custom thread classes named Thread_1 and Thread_2. These classes are likely subclasses of Qt's QThread class and are used to represent separate threads of execution.
  • QObject::connect( ) line establishes a connection between Thread_1 and Thread_2 using the Qt signal and slot mechanism. When a signal named sigThread1() is emitted by thread1, it will trigger the execution of the slot slotThread2() in thread2. The QueuedConnection indicates that the signal-slot connection will be made using a queued connection, which means the slot will be executed in the event loop of thread2.
  • thread2.get()->start() and thread1.get()->start() : These lines start the execution of Thread_2 and Thread_1, respectively. This means that both threads will run concurrently.

Thread_1.h” file is as follow;

Thread_1.h

Thread_1 class is a subclass of Qt’s QThread class.This class represents a custom thread for your Qt-based application.

Q_OBJECT macro macro is used to enable the Qt's meta-object system for the class. It is necessary when defining signals and slots within a class derived from QObject to enable Qt's signal-slot mechanism.

run() function is an override of the run method of the QThread class. The run method is the entry point for the thread's execution.

The sigThread1() signal is defined in the class and will be used to communicate with other objects connected to this thread.

When you create an instance of Thread_1 and call start() on it, the run() method will be executed in a separate thread, and it will emit the sigThread() signal, which can be connected to slots in other objects for further processing or coordination between threads.

Thread_2.h” file is as follow;

Thread_2.h

Thread_2 class is similar to Thread_1 class. When Thread_2 is started, it will call the run function and only display the log on the screen.There is a slot as you seen. When this slot is called, it logs messages indicating the start and finish of the slot’s execution. In between, it calls QThread::msleep(250) to pause the thread's execution for 250 milliseconds.

As you can see in the main.cpp file, our connection type is Qt::QueuedConnection. So A queued connection is established, meaning the signal is placed in an event queue and executed in the receiver’s thread event loop.

Our screen output in this case is as follows;

Output

Yes as we expected! As it seems, the threads started, Thread_1 threw the signal and finished its work. Thread_1 continued its operations without waiting for the slot operation executed by Thread_2 to finish.

So how is this situation in the case of Qt::BlockingQueuedConnection?

Let’s change the connection type in main.cpp as follows;

BlockingQueuedConnection

When we run the code again, the result is as follows;

Output

As it seems, Threads started working. Thread_1 threw a signal and the slot function executed by Thread_2 started. Thread_1 could not take any other action until the slot function finished. When the slot function finished, Thread_1 could continue its operations.

--

--