如何在QT中停止一个qThread
How to stop a qThread in QT
我想知道如何正确停止 QThread。我在线程中有一个无限循环,我想在执行特定操作时停止它:
我试过了:
if (thread->isRunning()){
worker->stop();
thread->terminate();
}
stop() 方法将值设置为 false 以跳出我的无限循环。
此外,我不太明白quit()、terminate() 或wait() 之间的区别。有人可以解释一下吗?
谢谢。
正确的答案取决于您实际使用 QThread
的方式以及您实施 stop()
的方式。
Qt 中的预期用例采用以下模型:
- 您创建了一个对象,该对象将响应信号做一些有用的工作
- 您创建了一个 `QThread` 并将您的对象移动到该线程
- 当您向对象发送信号时,它会在您创建的“QThread”中进行处理
现在您需要了解其实际实现方式的一些内部原理。 Qt 中有几个 "models" 信号,在某些情况下,当您 "send a signal" 时,您实际上只是简单地调用了一个 "slot" 函数。那是一个 "direct" 槽连接,在这种情况下 slot()
将在 调用者线程 中执行,一个发出信号。因此,为了与另一个线程通信,Qt 允许使用另一种信号,queued connections。调用者 不会调用 slot()
,而是将消息 留给拥有此槽的对象。与此对象关联的线程将读取此消息(在稍后的某个时间)并执行 slot()
本身。
现在您可以了解创建和执行时发生的情况 QThread
。一个新创建的线程将执行 QThread::run()
,默认情况下,将执行 QThread::exec()
这什么都不是,而是一个无限循环,为与线程关联的对象查找消息并将它们传输到这些对象的槽中。调用 QThread::quit()
向该队列发送终止消息。当 QThread::exec()
将读取它时,它将停止进一步处理事件,退出无限循环并轻轻终止线程。
现在,您可能已经猜到了,要收到终止消息,必须满足两个条件:
- 你应该运行`QThread::exec()`
- 您应该退出当前为 运行
的插槽
当人们从 QThread
继承并用自己的代码覆盖 QThread::run
时,通常会违反第一个。在大多数情况下,这是一种错误的用法,但它仍然被广泛教授和使用。在您的情况下,您似乎违反了第二个要求:您的代码运行无限循环,因此 QThread::exec()
根本无法获得控制权,也没有任何机会检查它是否需要退出。把你的那个无限循环扔到回收站,QThread::exec()
已经是 运行 这样的循环了。想一想如何重写您的代码,使其 不会 运行 无限循环,这总是可能的。根据 "messages-to-thread" 概念考虑您的程序。如果您定期检查某些内容,请创建一个 QTimer
,它将向您的对象发送消息并在您的插槽中实施检查。如果您处理大量数据,请将这些数据拆分为更小的块并写入您的对象,以便它一次处理 一个块 以响应某些消息。例如。如果您正在逐行处理图像,请制作一个插槽 processLine(int line)
并将一系列信号“0、1、2 ... height-1”发送到该插槽。请注意,您还必须在完成处理后显式调用 QThread::quit()
,因为事件循环是无限的,当您处理图像的所有行时它不会 "know"。还可以考虑对计算密集型任务使用 QtConcurrent
而不是 QThread
。
现在,QThread::terminate()
确实以非常不同的方式停止线程。它只是要求 OS 终止您的线程。 OS 只会在代码中的任意位置突然停止您的线程。线程堆栈内存将被释放,但此堆栈 指向 的任何内存都不会。如果线程拥有某些资源(例如文件或互斥量),它永远不会释放它。涉及将数据写入内存的操作可能会在中间停止,并使内存块(例如对象)未完全填充并处于无效状态。正如你可能从这个描述中猜到的,你永远不应该调用 ::terminate()
,除非极少数情况下保持线程的 运行 比内存和资源泄漏更糟糕。
QThread::wait()
只是一个方便的函数,等待 QThread
停止执行。它适用于 exit()
和 terminate()
。
您还可以实现您自己的线程系统,它是 QThread
的子类,并实现您自己的线程终止程序。从本质上讲,退出线程所需要做的只是在必要时从 QThread::run()
到 return,并且不能为此目的使用 exit()
和 terminate()
。创建您自己的同步原语并使用它向 return 发送您的代码。但在大多数情况下,这不是一个好主意,请记住(除非你自己使用 QEventLoop
),Qt 信号和插槽在这种情况下将无法正常工作。
我想知道如何正确停止 QThread。我在线程中有一个无限循环,我想在执行特定操作时停止它:
我试过了:
if (thread->isRunning()){
worker->stop();
thread->terminate();
}
stop() 方法将值设置为 false 以跳出我的无限循环。
此外,我不太明白quit()、terminate() 或wait() 之间的区别。有人可以解释一下吗?
谢谢。
正确的答案取决于您实际使用 QThread
的方式以及您实施 stop()
的方式。
Qt 中的预期用例采用以下模型:
- 您创建了一个对象,该对象将响应信号做一些有用的工作
- 您创建了一个 `QThread` 并将您的对象移动到该线程
- 当您向对象发送信号时,它会在您创建的“QThread”中进行处理
现在您需要了解其实际实现方式的一些内部原理。 Qt 中有几个 "models" 信号,在某些情况下,当您 "send a signal" 时,您实际上只是简单地调用了一个 "slot" 函数。那是一个 "direct" 槽连接,在这种情况下 slot()
将在 调用者线程 中执行,一个发出信号。因此,为了与另一个线程通信,Qt 允许使用另一种信号,queued connections。调用者 不会调用 slot()
,而是将消息 留给拥有此槽的对象。与此对象关联的线程将读取此消息(在稍后的某个时间)并执行 slot()
本身。
现在您可以了解创建和执行时发生的情况 QThread
。一个新创建的线程将执行 QThread::run()
,默认情况下,将执行 QThread::exec()
这什么都不是,而是一个无限循环,为与线程关联的对象查找消息并将它们传输到这些对象的槽中。调用 QThread::quit()
向该队列发送终止消息。当 QThread::exec()
将读取它时,它将停止进一步处理事件,退出无限循环并轻轻终止线程。
现在,您可能已经猜到了,要收到终止消息,必须满足两个条件:
- 你应该运行`QThread::exec()`
- 您应该退出当前为 运行
当人们从 QThread
继承并用自己的代码覆盖 QThread::run
时,通常会违反第一个。在大多数情况下,这是一种错误的用法,但它仍然被广泛教授和使用。在您的情况下,您似乎违反了第二个要求:您的代码运行无限循环,因此 QThread::exec()
根本无法获得控制权,也没有任何机会检查它是否需要退出。把你的那个无限循环扔到回收站,QThread::exec()
已经是 运行 这样的循环了。想一想如何重写您的代码,使其 不会 运行 无限循环,这总是可能的。根据 "messages-to-thread" 概念考虑您的程序。如果您定期检查某些内容,请创建一个 QTimer
,它将向您的对象发送消息并在您的插槽中实施检查。如果您处理大量数据,请将这些数据拆分为更小的块并写入您的对象,以便它一次处理 一个块 以响应某些消息。例如。如果您正在逐行处理图像,请制作一个插槽 processLine(int line)
并将一系列信号“0、1、2 ... height-1”发送到该插槽。请注意,您还必须在完成处理后显式调用 QThread::quit()
,因为事件循环是无限的,当您处理图像的所有行时它不会 "know"。还可以考虑对计算密集型任务使用 QtConcurrent
而不是 QThread
。
现在,QThread::terminate()
确实以非常不同的方式停止线程。它只是要求 OS 终止您的线程。 OS 只会在代码中的任意位置突然停止您的线程。线程堆栈内存将被释放,但此堆栈 指向 的任何内存都不会。如果线程拥有某些资源(例如文件或互斥量),它永远不会释放它。涉及将数据写入内存的操作可能会在中间停止,并使内存块(例如对象)未完全填充并处于无效状态。正如你可能从这个描述中猜到的,你永远不应该调用 ::terminate()
,除非极少数情况下保持线程的 运行 比内存和资源泄漏更糟糕。
QThread::wait()
只是一个方便的函数,等待 QThread
停止执行。它适用于 exit()
和 terminate()
。
您还可以实现您自己的线程系统,它是 QThread
的子类,并实现您自己的线程终止程序。从本质上讲,退出线程所需要做的只是在必要时从 QThread::run()
到 return,并且不能为此目的使用 exit()
和 terminate()
。创建您自己的同步原语并使用它向 return 发送您的代码。但在大多数情况下,这不是一个好主意,请记住(除非你自己使用 QEventLoop
),Qt 信号和插槽在这种情况下将无法正常工作。