Если я правильно понимаю следующий код из документации QFutureWatcher, то между последними строками есть условие гонки:
// 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);
Если функция ...
в QtConcurrent::run(...)
заканчивается до вызова следующей строки, затем watcher.finished()
сигнал никогда не сработает. Правильно ли мое предположение? Как мне обойти эту ошибку?
От http://doc.qt.io/qt-4.8/qfuturewatcher.html#setFuture
Один из сигналов может быть излучен для текущего состояния
будущее. Например, если будущее уже остановлено, готово
сигнал будет излучаться.
Другими словами, если QtConcurrent::run(...)
завершается раньше setFuture
называется, setFuture
будет по-прежнему излучать сигнал о текущем состоянии QFuture
, Таким образом, вам не нужно ничего делать, чтобы избежать состояния гонки.
Однако, в зависимости от остальной части вашего кода, вам может потребоваться позвонить QFuture::waitForFinished()
для того, чтобы ваш MyClass
, QFuture
а также QFutureWatcher
не выходи за рамки до QtConcurrent::run(...)
завершается.
Я запускал этот разрез в модульном тесте и QSignalSpy
не получал сигналы от QFutureWatcher
, Я решил проблему, позвонив явно QCoreApplication::processEvents()
до проверки:
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);
Сигнал, вероятно, испускается из потока, и в этой ситуации сигнал ставится в очередь вместо непосредственного выполнения.