2017-03-08 178 views
1

我想知道如何正确地停止QThread。我havea无限循环中的一个线索,我想阻止它,当我做了具体的行动:如何在QT中停止qThread

我曾尝试:

if (thread->isRunning()){ 
    worker->stop(); 
    thread->terminate(); 
} 

的stop()方法设置一个值,以假出去我的无限循环。此外,我并不真正了解quit(),terminate()或wait()之间的区别。有人能解释我吗?

谢谢。

+0

关于'terminate':_“警告:这个函数是危险的,它的使用是不鼓励的,线程可以在其代码路径的任何一点被终止,线程可以在修改数据时被终止,线程没有机会自行清理,解锁任何持有的互斥锁等。总之,只有在绝对必要时才使用此功能。“_ source:http://doc.qt.io/qt-4.8/qthread.html#terminate。其余的文件中你不明白的是什么? –

+0

是的,我知道这是危险的,这就是为什么我想知道如何正确地停止线程。 – iAmoric

+0

在文档中,似乎这两个方法(带有exit())都告诉线程循环退出。我真的没有看到差异 – iAmoric

回答

1

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

的Qt中打算用例假定以下模型:

  • 您创建一个对象,会做一些有益的工作,以响应信号
  • 您创建的QThread并移动对象到这个线程
  • 当你发送一个信号给你的对象时,它就在你创建的QThread中处理了

现在你需要了解一些内部的实际内容。在Qt中有几个“模型”的信号,在某些情况下,当您“发送信号”时,您只需调用一个“插槽”功能。这是一个“直接”插槽连接,在这种情况下,slot()将在调用者线程中执行,其中一个提示信号。所以为了与另一个线程通信,Qt允许使用另一种信号,即“排队连接”。呼叫者不会调用槽(),而是将消息留给拥有该槽的对象。与此对象关联的线程将读取此消息(稍后的一段时间)&执行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()以一种非常不同的方式停止线程。它只是要求操作系统杀死你的线程。操作系统会简单地在代码中的任意位置突然停止线程。线程堆栈内存将被free'd,但任何内存这个堆栈指向不会。如果线程拥有一些资源(如文件或互斥体),它永远不会释放它。涉及将数据写入存储器的操作可以在中间停止,并且使存储器块(例如对象)不完全填充并且处于无效状态。正如你可能从这个描述中猜到的那样,你永远不应该调用:: terminate(),除非极少数情况下,保持线程运行比获取内存资源泄漏更差。

QThread :: wait()只是一个方便的函数,一直等到QThread停止执行。它将与exit()和terminate()一起工作。

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