Implementing Multithreading in Qt with moveToThread and Synchronization
Using moveToThread for Worker Threads
This approach invovles moving a worker object to a dedicated thread, enabling background task execution. Synchronization is achieved using QMutex and QWaitCondition, particularly when the worker thread suspends itself and awaits a signal from the main thread.
Header File: TaskProcessor.h
#ifndef TASKPROCESSOR_H
#define TASKPROCESSOR_H
#include <QObject>
#include <QMutex>
#include <QWaitCondition>
class TaskProcessor : public QObject
{
Q_OBJECT
public:
explicit TaskProcessor(QObject* parent = nullptr);
public slots:
void executeTask();
void resumeTask();
signals:
void taskResumed();
void taskInitiated();
private slots:
void handleResume();
void handleInitiation();
private:
QMutex lock;
QWaitCondition pauseCondition;
};
#endif // TASKPROCESSOR_H
Implementation File: TaskProcessor.cpp
#include "TaskProcessor.h"
#include <QDebug>
#include <QThread>
TaskProcessor::TaskProcessor(QObject *parent)
: QObject{parent}
{
connect(this, &TaskProcessor::taskInitiated, this, &TaskProcessor::handleInitiation);
connect(this, &TaskProcessor::taskResumed, this, &TaskProcessor::handleResume);
}
void TaskProcessor::executeTask()
{
qDebug() << QThread::currentThreadId() << "Executing task";
emit taskInitiated();
}
void TaskProcessor::resumeTask()
{
qDebug() << QThread::currentThreadId() << "Resuming task";
qDebug() << QThread::currentThreadId() << "Signaling condition";
pauseCondition.wakeAll();
}
void TaskProcessor::handleResume()
{
qDebug() << QThread::currentThreadId() << "Resume handled";
}
void TaskProcessor::handleInitiation()
{
qDebug() << QThread::currentThreadId() << "Initiation handled";
int counter = 0;
while (true)
{
lock.lock();
qDebug() << QThread::currentThreadId() << "Iteration" << counter;
QThread::sleep(1);
++counter;
if (counter % 5 == 0)
{
qDebug() << QThread::currentThreadId() << "Waiting at" << counter;
pauseCondition.wait(&lock);
}
lock.unlock();
}
}
Header File: Manager.h
#ifndef MANAGER_H
#define MANAGER_H
#include <QObject>
class TaskProcessor;
class Manager : public QObject
{
Q_OBJECT
public:
explicit Manager(QObject* parent = nullptr);
~Manager();
public slots:
Q_INVOKABLE void startTask();
Q_INVOKABLE void suspendTask();
Q_INVOKABLE void continueTask();
Q_INVOKABLE void validate();
private:
QThread* workerThread;
TaskProcessor* processor;
};
#endif // MANAGER_H
Implementation File: Manager.cpp
#include "Manager.h"
#include <QDebug>
#include <QThread>
#include "TaskProcessor.h"
Manager::Manager(QObject *parent)
: QObject{parent}
{
qDebug() << "Manager initialized";
workerThread = new QThread;
processor = new TaskProcessor;
processor->moveToThread(workerThread);
workerThread->start();
}
Manager::~Manager()
{
qDebug() << QThread::currentThreadId() << "Manager cleanup";
workerThread->terminate();
if (workerThread->wait())
{
delete processor;
delete workerThread;
}
qDebug() << QThread::currentThreadId() << "Cleanup complete";
}
void Manager::startTask()
{
qDebug() << QThread::currentThreadId() << "Starting task";
processor->executeTask();
}
void Manager::suspendTask()
{
qDebug() << QThread::currentThreadId() << "Suspending task";
// Suspension logic placeholder
}
void Manager::continueTask()
{
qDebug() << QThread::currentThreadId() << "Continuing task";
processor->resumeTask();
}
void Manager::validate()
{
qDebug() << QThread::currentThreadId() << "Validation call";
}
QWaitCondition Methods
wakeAll
This method awakens all threads waiting on the condition. The order of awakening depends on the operating system's scheduling and cannot be predetermined.
wakeOne
This method awakens a single thread waiting on the condition. The specific thread awakened is determined by the OS scheduler. To target a particular thread, use separate wait conditions for different threads.
References
- QThread Class | Qt Core 5.15.15
- QThreadPool Class | Qt Core 5.15.15
- Synchronizing Threads | Qt 5.15
- QWaitCondition Class | Qt Core 5.15.15
- Wait Conditions Example | Qt Core 5.15.15