Qt provides a QThread class for creating multi-threaded applications. Unfortunately, there is some confusion about how to use QThread. This post talks about the foundation laid out in QThread class, and also describes how you should use Q-streams in your applications.
Do not create subclasses of QThread!
Most of the confusion is due to the fact that QThread is used as an abstract class. Thus, the only way to use QThread is to create its subclass and override the run() method. And it really was so, to the version of Qt 4.4, from which the QThread::run() method got the default implementation, hence the need to create the descendants of the QThread class has disappeared. The main reason for this was the fact that creating children of the QThread class can prevent the use of slots by the subclass.
The only reason you still need to create descendants of the QThread class is to create your own application run-loop.
Use moveToThread() and the “working” class, a subclass of QObject.
Here’s how you should implement a multi-threaded operation using the QThread class.
First, create a “working” class that inherits from the QObject class.
This class should determine the following signals and slots:
- The slot in which all the main work takes place.
- A signal that informs the calling code about the shutdown.
- * Optional, a signal that informs the calling code in case of errors.
Working class can be implemented this way:
class Worker : public QObject
void error(QString err);
Next, use QThread in conjunction with your “working” class, to perform multi-threaded work:
// Create thread
QThread* thread = new QThread;
Worker* worker = new Worker();
// Delegate ownership rights of working class to the QThread class
// Connect error signal to the slot which processes it
connect(worker, SIGNAL(error(QString)), this, SLOT(errorHandler(QString)));
// Connect signal `started` with process slot of working class
connect(thread, SIGNAL(started()), worker, SLOT(process()));
// Exit thread on finish and delete working class
connect(worker, SIGNAL(finished()), thread, SLOT(quit()));
connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));
// Delete thread after operation is performed
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));