我试图告诉一个线程优雅地退出。为此,线程在每次迭代中检查一个全局布尔标志,该标志指示线程是否应该继续或退出。线程是这样设置的(代码来自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
更新
我做了一些调试,发现了一些有趣的东西:
- 线程在其事件循环(QEventLoop::exec)中阻塞。它等待它显然没有收到的 quit() 信号。
- 线程的事件循环是在process() 返回后创建的。通过像我一样连接信号,线程的 run() 方法在线程已经完成它的工作之后被调用(例如 process() 返回)。
- 事件循环在执行实际循环之前清除所有已发布的退出事件。
我的结论
- 像我一样连接 quit() 插槽不起作用,因为在建立事件循环时会删除 quit() 事件
- 直接在线程对象上调用 quit() 成员函数显然会导致优雅终止。这可以通过使用 QThread::currentThread()->quit() 从外部或内部完成;
开放式问题
- 有没有办法在事件循环建立后调用 process() 方法?
- 在工作完成后创建事件循环感觉不对。但是,我使用 QThread 的方式与文档一致