Qt Signal-Slot Connection Types Explained
Signal-Slot Connection Types in Qt
Connection Type Overview
Qt provides several connection types that determine how slot functions are invoked when signals are emitted:
- Qt::DirectConnection - Immediate invocation
- Qt::QueuedConnection - Asynchronous invocation
- Qt::BlockingQueuedConnection - Synchronous invocation
- Qt::AutoConnection - Default connection type
- Qt::UniqueConnection - Single connection enforcement
Key Concepts
The connection type determines the behavior when a slot function is called:
- Each thread maintains its own event queue
- Threads receive signals through their event queues
- Signals are processed within event queues
Implementation Examples
Receiver Class Definition
#ifndef RECEIVER_H
#define RECEIVER_H
#include <QObject>
class Receiver : public QObject
{
Q_OBJECT
public:
explicit Receiver(QObject *parent = nullptr);
protected slots:
void handleSignal();
};
#endif
Receiver Implementation
#include "Receiver.h"
#include <QDebug>
#include <QThread>
Receiver::Receiver(QObject *parent) : QObject(parent)
{
}
void Receiver::handleSignal()
{
qDebug() << "Receiver::handleSignal() thread ID=" << QThread::currentThreadId();
}
Emitter Thread Definition
#ifndef EMITTERTHREAD_H
#define EMITTERTHREAD_H
#include <QThread>
class EmitterThread : public QThread
{
Q_OBJECT
public:
explicit EmitterThread(QObject *parent = nullptr);
signals:
void customSignal();
protected:
void run() override;
};
#endif
Emitter Thread Implementation
#include "EmitterThread.h"
#include <QDebug>
EmitterThread::EmitterThread(QObject *parent) : QThread(parent)
{
}
void EmitterThread::run()
{
qDebug() << "EmitterThread::run() thread ID=" << QThread::currentThreadId();
for(int count = 0; count < 2; count++)
{
qDebug() << "EmitterThread::run() iteration=" << count;
sleep(1);
}
emit customSignal();
qDebug() << "EmitterThread::run() completed";
}
Connection Type Demonstrations
#include <QCoreApplication>
#include "Receiver.h"
#include "EmitterThread.h"
#include <QDebug>
void demonstrateDirectConnection()
{
static Receiver receiver;
static EmitterThread emitter;
QObject::connect(&emitter, SIGNAL(customSignal()),
&receiver, SLOT(handleSignal()),
Qt::DirectConnection);
emitter.start();
emitter.wait(5000);
emitter.quit();
}
void demonstrateQueuedConnection()
{
static Receiver receiver;
static EmitterThread emitter;
QObject::connect(&emitter, SIGNAL(customSignal()),
&receiver, SLOT(handleSignal()),
Qt::QueuedConnection);
emitter.start();
emitter.wait(5000);
emitter.quit();
}
void demonstrateBlockingQueuedConnection()
{
static Receiver receiver;
static EmitterThread emitter;
QObject::connect(&emitter, SIGNAL(customSignal()),
&receiver, SLOT(handleSignal()),
Qt::BlockingQueuedConnection);
emitter.start();
emitter.wait(5000);
emitter.quit();
}
void demonstrateAutoConnection()
{
static Receiver receiver;
static EmitterThread emitter;
QObject::connect(&emitter, SIGNAL(customSignal()),
&receiver, SLOT(handleSignal()),
Qt::AutoConnection);
emitter.start();
emitter.wait(5000);
emitter.quit();
}
void demonstrateUniqueConnection()
{
static Receiver receiver;
static EmitterThread emitter;
QObject::connect(&emitter, SIGNAL(customSignal()),
&receiver, SLOT(handleSignal()),
Qt::UniqueConnection);
QObject::connect(&emitter, SIGNAL(customSignal()),
&receiver, SLOT(handleSignal()),
Qt::UniqueConnection);
emitter.start();
emitter.wait(5000);
emitter.quit();
}
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
qDebug() << "Main thread ID=" << QThread::currentThreadId();
// Uncomment one connection type to test
// demonstrateDirectConnection();
// demonstrateQueuedConnection();
// demonstrateBlockingQueuedConnection();
// demonstrateAutoConnection();
demonstrateUniqueConnection();
return app.exec();
}
Connection Type Behavior Analysis
Qt::DirectConnection - Immediate Invocation
The slot function is called directly in the thread that emits the signal, equivalent to real-time function calling.
// Output example:
// Main thread ID= 0x1abc
// EmitterThread::run() thread ID= 0x191c
// EmitterThread::run() iteration= 0
// EmitterThread::run() iteration= 1
// Receiver::handleSignal() thread ID= 0x191c
// EmitterThread::run() completed
Qt::QueuedConnection - Asynchronous Invocation
The signal is posted to the target thread's event queue and processed by that thread, while the current thread continues execution.
// Output example:
// Main thread ID= 0x1aec
// EmitterThread::run() thread ID= 0x1b5c
// EmitterThread::run() iteration= 0
// EmitterThread::run() iteration= 1
// EmitterThread::run() completed
// Receiver::handleSignal() thread ID= 0x1aec
Qt::BlockingQueuedConnection - Synchronous Invocation
The signal is posted to the target thread's event queue, and the current thread waits for the slot function to return before continuing exectuion. The target thread must be different from the current thread.
// Output example:
// Main thread ID= 0x18c4
// EmitterThread::run() thread ID= 0x1bf8
// EmitterThread::run() iteration= 0
// EmitterThread::run() iteration= 1
// Receiver::handleSignal() thread ID= 0x18c4
// EmitterThread::run() completed
Qt::AutoConnection - Default Connection
This is the default connection type and the most commonly used in Qt applications.
// Output example:
// Main thread ID= 0x1988
// EmitterThread::run() thread ID= 0x1970
// EmitterThread::run() iteration= 0
// EmitterThread::run() iteration= 1
// EmitterThread::run() completed
// Receiver::handleSignal() thread ID= 0x1988
Qt::UniqueConnection - Single Connection Enforcement
Functions identically to AutoConnection but ensures that the same signal can only be connected to the same slot function once, preventing multiple connections.
// Output example:
// Main thread ID= 0x37c
// EmitterThread::run() thread ID= 0x1b70
// EmitterThread::run() iteration= 0
// EmitterThread::run() iteration= 1
// EmitterThread::run() completed
// Receiver::handleSignal() thread ID= 0x37c