Платформа: Win7 x64, MinGW-rubenvb (4.7.2-x64), Qt 4.8
Скажем, у меня есть несколько длинных задач (чтение файла заполнения, запись файла заполнения и запуск симуляции), порожденных с помощью QConcurrent :: run, следующим образом:
void MainWindow::runLengthyJob() {
/* some setup */
jobWatcher->setFuture(QConcurrent::run(theApp, &AppClass::lengthyJob));
// lengthyJob - can be readPop(), writePop(), runSim()
}
Обычно выполнение этих задач занимает не менее 15 секунд (для моделирования требуется больше часов). Чтобы предотвратить сбой из еще не законченных потоков, я повторно реализую MainWindow :: closeEvent следующим образом:
void MainWindow::closeEvent(QCloseEvent *event) {
/* wait for any dangling thread */
if (QThreadPool::globalInstance()->activeThreadCount())
QThreadPool::globalInstance()->waitForDone();
event->accept();
} // end: MainWindow::closeEvent
Это работает нормально, но когда я нажимаю кнопку «x» в MainWindow, он кажется зависшим и показывает «Не отвечает» (я думаю, текст задан ОС), хотя это в итоге завершило работу приложения.
Я хочу выйти из приложения, как только будет запущен слот close () MainWindow. Итак, как я могу сократить время ожидания для еще не законченных потоков? Или как я могу уведомить пользователя о том, что все еще выполняется длинная работа (которая может занять несколько часов, прежде чем она полностью отключится)? (Я попытался включить QDialog / QMessagebox в closeEvent, но недавно созданные виджеты также зависли)
Примечание. Для AppClass: lengthyJobs [readPop () / writePop ()] это автономные функции, и я не могу разбить их на более мелкие шаги. Для AppClass :: runSim () возможны меньшие шаги.
Прежде всего, будущее, возвращаемое QtConcurrent :: run, не поддерживает отмену. Так что вы не можете просто отменить это. Лучшее, что вы можете сделать, это установить какой-либо флаг в AppClass и проверить его в ваших lengthyJobs (как вы сказали, это возможно в случае runSim), а затем дождаться завершения.
В любом случае, если вы хотите уведомить пользователя о запущенной задаче, вы можете сделать следующее: сделать подкласс QDialog, сказать WaitDialog с QTimer с некоторым периодом, запустить этот таймер при построении диалога, подключить сигнал timeout () к некоторому слоту в этом диалог и примите диалог, если нет запущенного потока:
if (QThreadPool::globalInstance()->activeThreadCount() == 0)
accept();
а затем в MainWindow :: closeEvent:
void MainWindow::closeEvent(QCloseEvent *event) {
WaitDialog dlg;
dlg.exec();
event->accept();
}
Других решений пока нет …