How can I use a QFutureWatcher with QtConcurrent::run() without a race condition
Asked Answered
M

2

11

If I understand the following code from the QFutureWatcher documentation correctly, then there is a race condition between the last to lines:

// Instantiate the objects and connect to the finished signal.
MyClass myObject;
QFutureWatcher<int> watcher;
connect(&watcher, SIGNAL(finished()), &myObject, SLOT(handleFinished()));

// Start the computation.
QFuture<int> future = QtConcurrent::run(...);
watcher.setFuture(future);

If the function ... in the QtConcurrent::run(...) finishes before the next line is called, then the watcher.finished() signal will never be triggered. Is my assumption correct? How do I work around this bug?

Macruran answered 21/9, 2012 at 8:46 Comment(0)
O
13

From http://doc.qt.io/qt-4.8/qfuturewatcher.html#setFuture

One of the signals might be emitted for the current state of the future. For example, if the future is already stopped, the finished signal will be emitted.

In other words, if QtConcurrent::run(...) completes before setFuture is called, setFuture will still emit a signal on the current state of the QFuture. So, you don't need to do anything in order to avoid a race condition.

However, depending on the rest of your code, you may need to call QFuture::waitForFinished() in order to ensure that your MyClass, QFuture and QFutureWatcher do not go out of scope before QtConcurrent::run(...) completes.

Oaks answered 21/9, 2012 at 8:50 Comment(0)
P
0

I was running this snipped in a unit test and QSignalSpy was not getting the signals from QFutureWatcher. I solved the issue by calling explicitely QCoreApplication::processEvents() before the check:

QFutureWatcher<int> watcher;
QSignalSpy spy(&watcher, &QFutureWatcher<int>::finished);

QFuture<int> future = QtConcurrent::run([](){
    qDebug() << "compute";
    return 42;
});
watcher.setFuture(future);
QCOMPARE(watcher.result(), 42);
QCOMPARE(spy.count(), 0);
QCoreApplication::processEvents();
QCOMPARE(spy.count(), 1);

The signal is probably emitted from a thread, and in this situation, the signal is queued instead of being directly executed.

Pinstripe answered 9/7, 2018 at 17:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.