如何在QT中停止qThread

iAm*_*ric 2 c++ qt qthread

我想知道如何正确停止QThread.我在一个线程中有一个无限循环,我想在我做一个特定的动作时停止它:

我试过了 :

if (thread->isRunning()){
    worker->stop();
    thread->terminate();
}
Run Code Online (Sandbox Code Playgroud)

stop()方法将值设置为false以退出无限循环.

此外,我真的不明白quit(),terminate()或wait()之间的区别.有人可以解释一下吗?

谢谢.

Ser*_*rov 7

一个正确的答案取决于你实际使用QThread的方式以及你如何实现stop().

Qt中的预期用例假设以下模型:

  • 您创建了一个对象,它将执行一些有用的工作来响应Signals
  • 您创建一个QThread并将您的对象移动到此线程
  • 当您向对象发送信号时,它会在您创建的QThread中处理

现在你需要了解一些实际实现方式的内部结构.Qt中有几种信号"模型",在某些情况下,当您"发送信号"时,您实际上只是简单地调用"插槽"功能.这是一个"直接"插槽连接,在这种情况下,slot()将在调用者线程中执行,一个引发信号.因此,为了与另一个线程通信,Qt允许另一种信号"排队连接".调用者不是调用slot(),而是将消息留给拥有此插槽的对象.与此对象关联的线程将读取此消息(稍后某个时间)并执行slot()本身的执行.

现在,您可以了解创建和执行QThread时发生的情况.新创建的线程将执行QThread :: run(),默认情况下,它将执行QThread :: exec(),但这是一个无限循环,它查找与线程关联的对象的消息并将它们传输到这些对象的插槽中.调用QThread :: quit()会向此队列发送终止消息.当QThread :: exec()读取它时,它将停止进一步处理事件,退出无限循环并轻轻终止线程.

现在,正如您可能猜到的,为了接收终止消息,必须满足两个条件:

  • 你应该运行QThread :: exec()
  • 您应该退出当前正在运行的插槽

当人们从QThread继承并使用他们自己的代码覆盖QThread :: run时,通常会违反第一个.在大多数情况下,这是错误的用法,但它仍然被广泛传授和使用.在你的情况下,似乎你违反了第二个要求:你的代码运行无限循环,因此QThread :: exec()根本没有得到控件,也没有机会检查它是否需要退出.将你的无限循环丢弃到回收站,QThread :: exec()已经为你运行了这样的循环.想一想如何重新编写代码,使其运行无限循环,这总是可行的.根据"消息到线程"概念来考虑您的程序.如果您定期检查某些内容,请创建一个QTimer,它将向您的对象发送消息并在您的插槽中执行检查.如果处理大量数据,请将此数据拆分为较小的块并编写对象,以便一次处理一个块以响应某些消息.例如,如果您逐行处理图像,请创建一个槽processLine(int line)并将信号序列"0,1,2 ... height-1"发送到该槽.请注意,一旦完成处理,您还必须显式调用QThread :: quit(),因为事件循环是无限的,当您处理图像的所有行时它不会"知道".还要考虑将QtConcurrent用于QThread的计算密集型任务.

现在,QThread :: terminate()确实以一种非常不同的方式停止一个线程.它只是要求OS杀死你的线程.操作系统会简单地将您的线程突然停在代码中的任意位置.线程堆栈内存将是空闲的,但此堆栈指向的任何内存都不会.如果一个线程拥有某些资源(例如文件或互斥),它将不会释放它.涉及将数据写入存储器的操作可以在中间停止并且使存储器块(例如,对象)不完全填充并且处于无效状态.正如你可能从这个描述中猜到的那样,你永远不应该调用:: terminate(),除非极少数情况下保持线程运行比获取内存和资源泄漏更糟糕.

QThread :: wait()只是一个便利函数,等待QThread停止执行.它将与exit()和terminate()一起使用.

您还可以从QThread实现自己的子类的线程系统,并实现自己的线程终止过程.退出线程所需要的只是在必要时从QThread :: run()返回,并且你不能同时使用exit()和terminate().创建自己的同步原语并使用它来表示要返回的代码.但在大多数情况下,这不是一个好主意,请记住(除非你自己使用QEventLoop),Qt信号和插槽在这种情况下将无法正常工作.