我试图告诉一个线程优雅地退出。为此,线程在每次迭代中检查全局布尔标志,该标志指示线程是否应该继续或退出。线程是类似这样的设置(代码为http://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/):为什么我的线程不能正常退出?
ImageFusionQt::ImageFusionQt(QWidget* parent)
: QMainWindow(parent)
{
captureThread = new QThread();
captureWorker = new CaptureWorker();
// Connects the threads started() signal to the process() slot in the worker, causing it to start.
connect(captureThread, SIGNAL(started()), captureWorker, SLOT(process()));
// Connect worker finished signal to trigger thread quit, then delete.
connect(captureWorker, SIGNAL(finished()), captureThread, SLOT(quit()));
connect(captureWorker, SIGNAL(finished()), captureWorker, SLOT(deleteLater()));
// Make sure the thread object is deleted after execution has finished.
connect(captureThread, SIGNAL(finished()), captureThread, SLOT(deleteLater()));
// Give QThread ownership of Worker Object
captureWorker->moveToThread(captureThread);
captureThread->start();
}
CaptureWorker.cpp
void CaptureWorker::process()
{
while(true)
{
g_exit_lock->lockForRead();
if(g_exit)
{
g_exit_lock->unlock();
break;
}
g_exit_lock->unlock();
}
qDebug() << "CaptureWorker: Exiting.";
emit finished();
}
现在,当我试图通过一些功能的标志设置为true停止线程时, process()方法返回,但线程没有完成,wait()的调用永远阻塞。为什么我的线程不终止?
g_exit_lock->lockForWrite();
g_exit = true;
g_exit_lock->unlock();
QThread::sleep(15);
qDebug() << "ct finished? " << captureThread->isFinished();
captureThread->wait();
qDebug() << "All threads stopped.";
日志文件输出:
2013.03.26 09:29:22[D] CaptureWorker: Exiting.
2013.03.26 09:29:37[D] ct finished? false
UPDATE
我做了一些调试,发现了一些野趣的东西:
- 在事件循环的线程块(QEventLoop :: EXEC)。它等待显然没有收到的quit()信号。
- 线程的事件循环在 process()返回后创建。通过像我一样连接信号,线程的run()方法在线程完成其工作(例如返回的process())后被调用。
- 事件循环会在执行实际循环之前清除所有已发布的退出事件。
我的结论
- 连接,因为我根本不起作用,因为退出()当事件循环建立
- 调用Quit()成员事件被删除的退出()槽函数直接在线程对象上,显然会导致优美的终止。这可以通过使用QThread :: currentThread() - > quit();从外部或从内部完成。
开放性问题
- 有没有办法来调用process()方法的事件循环已经建立之后?
- 感觉不对,事情循环是在工作完成时创建的。但是,我使用QThread的方式与docs
也许你只需要刷新调试流? – Nick 2013-03-26 09:02:46
finished()的内容是什么? – 2013-03-26 09:23:41
日志记录是一种*非常*非生产性的方式来调试程序。学习如何使用调试器。只需连接调试器,中断程序,将上下文切换到工作线程,并从堆栈跟踪中找出它正在做什么。有很高的可能性,你现在会发现它不是执行循环,而是埋在某种操作系统调用中,等待捕获完成。所以它不会测试g_exit,所以它不会退出。 – 2013-03-26 10:10:36