我試圖告訴一個線程優雅地退出。爲此,線程在每次迭代中檢查全局布爾標誌,該標誌指示線程是否應該繼續或退出。線程是類似這樣的設置(代碼爲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