c++ - 为什么我的线程不能正常退出?

标签 c++ multithreading qt visual-c++ qt5

我试图告诉一个线程优雅地退出。为此,线程在每次迭代中检查一个全局 bool 标志,指示线程是继续还是退出。线程设置如下(代码来自 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();

}

捕获工作器.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的方式是符合docs

最佳答案

这里发生的是 quit 根本没有被调用。 你知道 Qt 有直接或排队的连接。当你使用这个

connect(captureWorker, SIGNAL(finished()), captureThread, SLOT(quit()));

它真的是一个自动连接类型。所以因为你将 captureWorker 移动到另一个线程,Qt::QueuedConnecton用来。 quit() 将在ma​​in 线程上调用。但是您所做的是使用 captureThread->wait();
阻塞主线程 quit() 在事件循环中排队,但由于等待线程完成而被阻塞。
所以你可能想通过替换

来直接调用 quit()
connect(captureWorker, SIGNAL(finished()), captureThread, SLOT(quit()));

connect(captureWorker, SIGNAL(finished()), captureThread, SLOT(quit()), Qt::DirectConnection);

或者像您在编辑中建议的那样直接调用 quit(),或者您也可以执行类似以下操作而不是 captureThread->wait(); 如果您确实需要

  QEventLoop l;
  l.connect(captureThread, SIGNAL(finished()), SLOT(quit()));  
  l.exec(QEventLoop::ExcludeUserInputEvents);

或者,您可以连接到线程的 finished() 信号,并在 captureThread->wait(); 之后执行任何您想执行的操作,这样您就完全不必手动等待。
在 Qt 中有很多做事的方式

关于c++ - 为什么我的线程不能正常退出?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15632868/

相关文章:

C++ 为什么在与 void 指针一起使用时 sprintf_s 格式会发生变化?

c++ - Windows 中的非主 GUI 线程究竟何时退出?

java - 防止 future.get() 使 GUI 无响应以实现暂停按钮

JavaFX并发任务设置状态

c++ - Qt windeployqt 导致部署不可用

c++ - 使用 qt c++ 为多种形式创建公共(public)数据库连接

python - QTextEdit.find() 在 Python 中不起作用

c++ - 覆盖 QTextEdit 子类中的 keyPressEvent

c++ - 如何从 TBitmap 获取像素数组?

c++ - 将方法作为参数传递给另一个方法,该方法本身将传递的方法传递给标准线程