Qt终止线程衍生QConcurrent::run

Qt terminate thread spawn by QConcurrent::run

本文关键字:QConcurrent run 终止 线程 Qt      更新时间:2023-10-16

平台: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"按钮,它似乎冻结并显示"不响应"(我猜文本是由操作系统给出的),虽然它最终终止了应用程序。

我想退出应用程序一旦关闭()槽的主窗口被触发。那么,如何缩短未完成线程的等待时间呢?或者我如何通知用户仍有一个很长的作业正在运行(在完全关闭之前可能需要几个小时)?(我试图包括QDialog/QMessagebox在closeEvent,但新创建的小部件也冻结)

注意:对于AppClass: lengthjobs [readPop()/writePop()],这些是自包含的函数,我不能分解为更小的步骤。对于AppClass::runSim(),可能需要更小的步骤

首先,QtConcurrent::run返回的future不支持取消。所以你不能消掉它。你能做的最好的事情就是在AppClass中设置一些标志,并在你的lengthyJobs中检查它(就像你说的,在runSim的情况下是可能的),然后等待完成。

无论哪种方式,如果你想通知用户正在运行的任务,你可以这样做:创建一个QDialog的子类,使用带有一定周期的QTimer来调用WaitDialog,在构建对话框时启动这个计时器,将timeout()信号连接到这个对话框中的某个槽,如果没有正在运行的线程,则接受这个对话框:

if (QThreadPool::globalInstance()->activeThreadCount() == 0)
    accept();

,然后在MainWindow::closeEvent:

void MainWindow::closeEvent(QCloseEvent *event) {
    WaitDialog dlg;
    dlg.exec();
    event->accept();
}