QThread::quit() 是立即结束线程还是等到返回事件循环?

Posted

技术标签:

【中文标题】QThread::quit() 是立即结束线程还是等到返回事件循环?【英文标题】:Does QThread::quit() immediately end the thread or does it wait until returning to the event loop? 【发布时间】:2014-05-28 23:13:48 【问题描述】:

有很多 Qt 多线程教程指出可以使用以下两行安全地停止 QThread

qthread.quit(); // Cause the thread to cease.
qthread.wait(); // Wait until the thread actually stops to synchronize.

我有很多代码在做这件事,在大多数停止线程的情况下,我总是会设置自己的取消标志并在执行期间经常检查它(这是常态)。到目前为止,我一直在想,调用 quit 可能会导致线程不再执行任何等待信号(例如,排队的信号将不再调用其插槽),但仍等待当前执行的插槽完成。

但我想知道我是否正确,或者quit() 是否实际上停止了它所在的线程的执行,例如,如果某些事情未完成,比如文件描述符尚未关闭,那么它肯定应该是,即使在大多数情况下,我的工作对象会清理这些资源,但如果我确切地知道 quit 是如何工作的,我会感觉更好。

我问这个是因为QThread::quit() 文档说它“相当于调用 QThread::exit(0)”。我相信这意味着线程将立即停止它所在的位置。但是调用退出的堆栈帧会发生什么?

【问题讨论】:

【参考方案1】:

QThread::quit 如果线程没有事件循环或线程中的某些代码阻塞了事件循环,则不执行任何操作。所以它不一定会停止线程。

所以QThread::quit 告诉线程的事件循环退出。调用它后,一旦控件返回到线程的事件循环,线程就会完成。

如果您正在阻塞事件循环,例如通过在循环中工作,您将不得不添加某种中止标志。这可以通过一个公共的或至少具有公共设置方法的布尔成员变量来完成。然后你可以通过设置 abort 标志来告诉线程尽快从外部退出(例如从你的主线程)。当然这需要你的线程代码定期检查中止标志。

您也可以通过QThread::terminate() 强制线程立即终止,但这是一种非常糟糕的做法,因为它可能会在其代码中未定义的位置终止线程,这意味着您最终可能会得到永远不会得到的资源释放和其他讨厌的东西。所以只有当你真的无法绕过它时才使用它。从其文档中:

警告:此功能很危险,不鼓励使用。线程可以在其代码路径中的任何位置终止。修改数据时可以终止线程。线程没有机会自行清理、解锁任何持有的互斥锁等。简而言之,只有在绝对必要时才使用此功能。

我认为当您在线程中使用循环时,这是完成线程的好方法:

myThread->m_abort = true; //Tell the thread to abort
if(!myThread->wait(5000)) //Wait until it actually has terminated (max. 5 sec)

  myThread->terminate(); //Thread didn't exit in time, probably deadlocked, terminate it!
  myThread->wait(); //We have to wait again here!

【讨论】:

感谢您的回答。是的,我总是在我的线程中使用取消(中止)标志,无论它们是否只是运行自己的处理循环。当涉及到运行 Qt 事件循环的 QThreads 时,我只是对使用 quit() 的情况感到好奇。 你也可以覆盖myThread's class' terminate(); slot (virtual void terminate();),这样你就可以随心所欲地回滚你所做的事情。想想在你自己的terminate(); 的末尾打电话给QThread::terminate();。 ;-)【参考方案2】:

如果您想使用 Qt 的内置功能,请尝试QThread::requestInterruption()

主线程

struct X 
  QThread m_Thread; 
  void Quit ()
  
    m_Thread.quit();
    m_Thread.requestInterruption();
  
;

X::m_Thread 引用的一些线程

while(<condition>) 
  if(QThread::currentThread()->isInterruptionRequested())
    return;
  ...

根据文档:

void QThread::requestInterruption()

请求中断线程。该请求是建议性的,由线程上运行的代码决定是否以及如何根据此类请求采取行动。此函数不会停止线程上运行的任何事件循环,也不会以任何方式终止它。

【讨论】:

以上是关于QThread::quit() 是立即结束线程还是等到返回事件循环?的主要内容,如果未能解决你的问题,请参考以下文章

qthreadnew不释放

立即安全地终止线程 (C#)

守护线程

Django异步任务线程池

java 多线程 System.exit; 是退出当前线程,还是结束整个虚拟机

java的while循环中被new的对象在一次循环结束后 会被垃圾回收吗?