How to block a thread until a slot is received

78 Views Asked by At

I'm using Qt 6.6.1.

I defined a class MyThread:

class MyThread: public QThread

As an inner class, I defined a class WakeUpEvent in the private section of the .h file:

private:
    class WakeUpEvent : public QEvent {
    public:
        static const QEvent::Type EventType = static_cast<QEvent::Type>(QEvent::User + 1);

        WakeUpEvent() : QEvent(EventType) {}
    };

Then, I override the event method:

protected:

    bool event(QEvent* event) override {
        if (event->type() == WakeUpEvent::EventType) {
            // Wake-up event received
            condition.wakeOne();
            return true;
        }

        return QThread::event(event);
    }

In the private section, I defined 3 variables:

QMutex mutex;
QWaitCondition condition;
bool shouldContinue;

Finally, I defined a public slot:

void MyThread::TaskCompleted()
{
    shouldContinue = false;

    // Send wake-up event to the thread
    QCoreApplication::postEvent(this, new WakeUpEvent());
}

In my code, I block the thread execution this way:

shouldContinue = true;
emit signalForAnotherThread();
// Sleep until wake-up event is received
while (shouldContinue) {
   mutex.lock();
   condition.wait(&mutex);
   mutex.unlock();
}

signalForAnotherThread is a signal to which is connected another thread that I can call thread2. thread2 will perform some tasks, and at the end, it will emit the signal to which the slot TaskCompleted is connected.

I'm sure, as I tested through breakpoints, that the signal from thread2 for the slot TaskCompleted is emitted. But TaskCompleted is never reached (I checked through breakpoint).

The last line code executed in MyThread block is:

condition.wait(&mutex);

What is my mistake?

TaskCompleted is connected to the signal emitted by thread2 this way:

connect(thread2, SIGNAL(tasksCompleted()), this, SLOT(TaskCompleted()), Qt::QueuedConnection);
1

There are 1 best solutions below

1
Edward Cohen On

I changed my approach, and now it is working.

In my MyThread class, I removed QMutex and QWaitCondition. I let only a bool value to decide if MyThread must continue its execution:

bool shouldContinue;

Then I execute this code:

//Do something -> thread logic
shouldContinue = false;
emit signalForAnotherThread();
WaitForCompletion(shouldContinue);
//Do something -> thread logic

WaitForCompletion is the following method:

void MyThread::WaitForCompletion(const bool &bTermination)
{
   //Waiting another thread completes its task and emits signal
   while (!bTermination)
   {
      //Process Events for max 100 msec.
      QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
      QThread::msleep(100);
   }
}

In the connect instruction, I abandoned the use of SIGNAL / SLOT macros as suggested.

connect(&thread2, &Thread2Class::taskCompleted, &myThread, &MyThread::TaskCompleted, Qt::QueuedConnection);

Finally, in TaskCompleted slot, I set up shouldContinue to true:

void MyThread::TaskCompleted()
{    
  shouldContinue = true;
}