If I understood correctly you want to send and receive signals from the main thread to your worker thread. The documentation explains pretty good how to do this:
class Worker : public QObject
{
Q_OBJECT
public slots:
void doWork(const QString ¶meter) {
QString result;
/* ... here is the expensive or blocking operation ... */
emit resultReady(result);
}
signals:
void resultReady(const QString &result);
};
class Controller : public QObject
{
Q_OBJECT
QThread workerThread;
public:
Controller() {
Worker *worker = new Worker;
worker->moveToThread(&workerThread);
connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);
connect(this, &Controller::operate, worker, &Worker::doWork);
connect(worker, &Worker::resultReady, this, &Controller::handleResults);
workerThread.start();
}
~Controller() {
workerThread.quit();
workerThread.wait();
}
public slots:
void handleResults(const QString &);
signals:
void operate(const QString &);
};
You must create a QObject
that will have a member function doing the operations you want to have in your separate thread. You move this QObject
to the QThread
you want to execute the operation in changing its affinity and send/receive signals to/from it.
In cases like these it is not necessary and not recommended to inherit QThread
. But if you do so, don't forget to call exec()
in the run()
member function so that the thread starts its own event loop(so that it can handle asynchronous operations).
So no, you don't need mutexes for your operations. The event loops of the main thread and worker thread can beautifully communicate, send signals to each other and synchronize.
I recommend looking at this Consume/Producer solution which synchronizes 2 threads and which was created by Bradley Hughes
back in 2006 when QThread::run()
wasn't starting the event loop by default. Here is an updated version of his example:
#include <QtCore>
#include <stdio.h>
enum {
Limit = 123456,
BlockSize = 7890
};
class Producer : public QObject
{
Q_OBJECT
QByteArray data;
int bytes;
public:
inline Producer() : bytes(0) { }
public slots:
void produce()
{
int remaining = Limit - bytes;
if (remaining == 0) {
emit finished();
return;
}
// this will never happen
if (data.size() != 0)
qFatal("Producer: Consumer failed to consume!");
int size = qMin(int(BlockSize), remaining);
bytes += size;
remaining -= size;
data.fill('Q', size);
printf("Producer: produced %d more bytes, %d of %d total\n", size, bytes, Limit);
emit produced(&data);
}
signals:
void produced(QByteArray *data);
void finished();
};
class Consumer : public QObject
{
Q_OBJECT
int bytes;
public:
inline Consumer() : bytes(0) { }
public slots:
void consume(QByteArray *data)
{
// this will never happen
if (data->size() == 0)
qFatal("Consumer: Producer failed to produce!");
int remaining = Limit - bytes;
int size = data->size();
remaining -= size;
bytes += size;
data->clear();
printf("Consumer: consumed %d more bytes, %d of %d total\n", size, bytes, Limit);
emit consumed();
if (remaining == 0)
emit finished();
}
signals:
void consumed();
void finished();
};
int main(int argc, char **argv)
{
QCoreApplication app(argc, argv);
// create the producer and consumer and plug them together
Producer producer;
Consumer consumer;
producer.connect(&consumer,
SIGNAL(consumed()),
SLOT(produce()));
consumer.connect(&producer,
SIGNAL(produced(QByteArray *)),
SLOT(consume(QByteArray *)));
// they both get their own thread
QThread producerThread;
producer.moveToThread(&producerThread);
QThread consumerThread;
consumer.moveToThread(&consumerThread);
// start producing once the producer's thread has started
producer.connect(&producerThread,
SIGNAL(started()),
SLOT(produce()));
// when the consumer is done, it stops its thread
consumerThread.connect(&consumer,
SIGNAL(finished()),
SLOT(quit()));
// when consumerThread is done, it stops the producerThread
producerThread.connect(&consumerThread,
SIGNAL(finished()),
SLOT(quit()));
// when producerThread is done, it quits the application
app.connect(&producerThread,
SIGNAL(finished()),
SLOT(quit()));
// go!
producerThread.start();
consumerThread.start();
return app.exec();
}
#include "main.moc"
Read here for more info.