如何在 QT 中停止 qThread [重复]

Posted

技术标签:

【中文标题】如何在 QT 中停止 qThread [重复]【英文标题】:How to stop a qThread in QT [duplicate] 【发布时间】:2017-07-29 12:29:02 【问题描述】:

我想知道如何正确停止 QThread。我在一个线程中有一个无限循环,我想在执行特定操作时停止它:

我试过了:

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

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

此外,我不太了解quit()、terminate() 或wait() 之间的区别。谁能解释一下?

谢谢。

【问题讨论】:

关于terminate: "警告:此函数很危险,不鼓励使用。线程可以在其代码路径中的任何位置终止。线程可以在修改数据时终止。线程没有机会自行清理、解锁任何持有的互斥锁等。简而言之,只有在绝对必要时才使用此功能。” 来源:doc.qt.io/qt-4.8/qthread.html#terminate。对于其余的文档中您不理解的内容? 是的,我知道这很危险,这就是为什么我想知道如何正确停止线程。 在文档中,似乎这两种方法(也带有 exit() )都告诉线程循环退出。我真的看不出有什么区别 使用std::atomic<bool>std::atomic_bool 变量。将其设置在您的 “特定操作” 中并在您的线程 proc 中对其进行测试并干净地退出。 另请参阅this answer,详细说明如何将您拥有的无限循环转换为与事件系统和排队插槽互操作的循环,从而更灵活、更易于使用。 【参考方案1】:

正确的答案取决于您实际使用QThread 的方式以及您如何实施stop()

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

您创建一个对象,该对象将做一些有用的工作来响应信号 您创建一个 `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() 确实以非常不同的方式停止线程。它只是要求操作系统杀死你的线程。操作系统只会在代码中的任意位置突然停止你的线程。线程堆栈内存将被释放,但该堆栈指向的任何内存都不会。如果一个线程拥有某些资源(例如文件或互斥锁),它将永远不会释放它。涉及将数据写入内存的操作可以在中间停止,并使内存块(例如对象)未完全填充并处于无效状态。正如你可能从这个描述中猜到的那样,你永远不应该调用::terminate(),除非在极少数情况下保持线程运行比内存和资源泄漏更糟糕。

QThread::wait() 只是一个方便的函数,它会等到QThread 停止执行。它适用于exit()terminate()

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

【讨论】:

以上是关于如何在 QT 中停止 qThread [重复]的主要内容,如果未能解决你的问题,请参考以下文章

在 qt 中使用 QThread 实现启动/停止/暂停

即使使用 QThread,QT 程序也会停止

如何在 Qt c++ 中管理 QThread?

QT-如何在 QThread 中使用 QWidget?

如何在 Qt 中正确终止 QThread?

QThread - 如何停止工人?