nilo
nilo

Reputation: 1130

QEventLoop for synchronous wait for signal

I'm using Qt5, QCoreApplication. In order to allow for readable and easy to maintain code, I need to write a blocking method in a class/thread A that will emit a signal, connected to a slot in a different thread B, and then wait for an answer or a timeout to occur asynchronously in thread B. I have first been thinking about what felt like a natural solution: let thread B reply with a signal connected to a slot in thread A, and somehow wait for it. It seems QEventLoop can do that for me. But I keep reading contradictory statements: that's the pattern but avoid it if you can :-). I'm pretty sure I could achieve my purpose by blocking A on a 0 QSemaphore that B would release when ready. The code would probably not be much more complex that way. What do you experienced Qt developers think? Is there a good solution or do you find some symptoms of flawed analysis in my description (i.e. do you think I should never ever need to do something like that? :-))?

Upvotes: 2

Views: 2582

Answers (2)

The key ingredient you can leverage is the Qt::BlockingQueuedConnection.

This connection type lets you pass return value from a slot. You can use it in a signal-slot connection. You can also directly invoke the slot without using a signal through the QMetaMethod::invoke / QMetaObject::invokeMethod mechanism.

#include <QDebug>
#include <QThread>
#include <QCoreApplication>

class Master : public QObject {
  Q_OBJECT
public:
  Q_SIGNAL bool mySignal();
  Q_SLOT void process() {
    if (mySignal()) { // this can be a blocking call
      qDebug() << "success!";
    }
    thread()->quit();
  }
};

class Slave : public QObject {
  Q_OBJECT
public:
  Q_SLOT bool mySlot() {
    // do whatever processing is needed here
    // It's OK to call QCoreApplication::processEvents here
    return true;
  }
};

int main(int argc, char** argv) {
  QCoreApplication app(argc, argv);
  QThread masterThread, slaveThread;
  Master master;
  Slave slave;
  master.moveToThread(&masterThread);
  slave.moveToThread(&slaveThread);
  slave.connect(&master, SIGNAL(mySignal()), SLOT(mySlot()),
                Qt::BlockingQueuedConnection);
  masterThread.start();
  slaveThread.start();
  QMetaObject::invokeMethod(&master, "process");
  masterThread.wait();
  slaveThread.quit();
  slaveThread.wait();
  return 0;
}

#include "main.moc"

Upvotes: 3

0xFFFFFFFF
0xFFFFFFFF

Reputation: 852

if you just want to emit a signal in your thread, which means your main thread will have a slot to connect you thread signal, it is simple, just emit it. but if you want a slot in your thread, and receive signal and so something in your thread, you have to use QEventloop in you run method.

usually, I will just use QThread::wait to wait for other thread end.

be careful here, some Qt objects cannot work across the thread like QSql* and QTcpSocket....

Upvotes: 0

Related Questions