Qt 通过 QConcurrent::run 终止线程生成
Posted
技术标签:
【中文标题】Qt 通过 QConcurrent::run 终止线程生成【英文标题】:Qt terminate thread spawn by QConcurrent::run 【发布时间】:2013-03-13 04:42:14 【问题描述】:平台: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
这工作正常,但是当我单击 MainWindow 的“x”按钮时,它似乎冻结并显示“无响应”(我猜文本是由操作系统给出的),尽管它最终终止了应用程序。
我想在 MainWindow 的 close() 槽被触发后立即退出应用程序。那么,如何缩短未完成线程的等待时间呢?或者我如何通知用户仍有一个冗长的作业正在运行(可能需要数小时才能完全关闭)? (我尝试在 closeEvent 中包含 QDialog/QMessagebox,但新创建的小部件也冻结了)
注意:对于 AppClass:longyJobs [readPop() /writePop()],这些是自包含的函数,我不能分解成更小的步骤。对于 AppClass::runSim(),可以使用更小的步骤。
【问题讨论】:
【参考方案1】:首先,由 QtConcurrent::run 返回的 future 不支持取消。所以你不能只是取消它。您可以做的最好的事情是在 AppClass 中设置一些标志并在您的 longyJobs 中检查它(正如您所说,在 runSim 的情况下是可能的),然后等待完成。
无论哪种方式,如果您想通知用户正在运行的任务,您可以执行以下操作:创建一个 QDialog 的子类,例如带有一段时间的 QTimer 的 WaitDialog,在对话框构建时启动此计时器,将 timeout() 信号连接到某个插入此对话框,如果没有正在运行的线程,则接受该对话框:
if (QThreadPool::globalInstance()->activeThreadCount() == 0)
accept();
然后在 MainWindow::closeEvent:
void MainWindow::closeEvent(QCloseEvent *event)
WaitDialog dlg;
dlg.exec();
event->accept();
【讨论】:
如果我将 QRunnable/QThread 子类化为任务,是否可以“取消”线程? 如果你将 QThread 子类化,你可以使用 QThread::terminate,尽管文档说它有潜在的危险,因为正在运行的线程不会有机会进行任何清理。以上是关于Qt 通过 QConcurrent::run 终止线程生成的主要内容,如果未能解决你的问题,请参考以下文章
如何确定在 Linux 上使用 Qt4 终止 QProcess 的信号?