1

Using a QEventLoop to block execution in a Qt program, how can you connect 10 individual signals to the one loop in such a way that it won't unblock until all 10 signals are received?

ChrisGPT was on strike
  • 127,765
  • 105
  • 273
  • 257

1 Answers1

0

Please avoid using nested loops when possible. But if you are absolutely sure that you have no way around, you need to have a way to store which of the signals have fired and which of them haven't, and quit the event loop (i.e. maybe by emitting a signal connected to your event loop's QEventLoop::quit) only when all signals have fired.

Here is a minimum example that uses 10 QTimers with different intervals, and waits for all of them to fire before quitting a nested event loop:

#include <QtCore>
#include <algorithm>

int main(int argc, char* argv[]) {
    QCoreApplication a(argc, argv);
    const int n = 10;
    //10 timers to emit timeout signals on different intervals
    QTimer timers[n];
    //an array that stores whether each timer has fired or not
    bool timerFired[n]= {};
    QEventLoop loop;
    //setup and connect timer signals
    for(int i=0; i<n; i++) {
        timers[i].setSingleShot(true);
        QObject::connect(&timers[i], &QTimer::timeout, [i, &timerFired, &loop]{
            qDebug() << "timer " << i << " fired";
            timerFired[i]=true;
            //if all timers have fired
            if(std::all_of(std::begin(timerFired), std::end(timerFired),
                           [](bool b){ return b; }))
                loop.quit(); //quit event loop
        });
        timers[i].start(i*i*100);
    }
    qDebug() << "executing loop";
    loop.exec();
    qDebug() << "loop finished";

    QTimer::singleShot(0, &a, &QCoreApplication::quit);
    return a.exec();
}
Mike
  • 8,055
  • 1
  • 30
  • 44
  • Would creating 10 threads be exactly the same thing as nesting loops? I kinda wanted to use 1 event to create 10 asynchronous tasks, then wait for them all to finish. I briefly read the link you provided, and it seems that this might be a no-no. – Steven Matias Dec 29 '17 at 01:34
  • They are definitely not the same thing, the term *nesting event loops* refers to having an event loop start another event loop within it (maybe as a response to some kind of event). Using threads is a completely different animal, threads provide parallel execution paths, you can use them to, say, execute two different things in parallel. In Qt, Threads can run event loops to be able to deliver events for `QObject`s that [*live in them*](https://doc.qt.io/qt-5/qobject.html#thread-affinity). – Mike Dec 29 '17 at 11:29
  • if you just want to start 10 asynchronous tasks, you can use [`QtConcurrent::run`](https://doc.qt.io/qt-5/qtconcurrentrun.html), this way, you don't have to manage the threads yourself. and you can wait for results either synchronously using [`QFuture::waitForFinished`](https://doc.qt.io/qt-5/qfuture.html#waitForFinished) or asynchronously by using a [`QFutureWatcher`](https://doc.qt.io/qt-5/qfuturewatcher.html) and connecting to its [`finished()`](https://doc.qt.io/qt-5/qfuturewatcher.html#finished) signal. – Mike Dec 29 '17 at 11:34