MyClass
对象有一个 worker QObject
,它在另一个线程中工作:
class MyClass {
....
private:
QThread thread;
Worker worker; // inherits QObject
};
...
worker.moveToThread(&thread);
现在,当我调用 thread.exit()
时,我的工作线程会立即停止。我希望它完成所有未决事件,然后退出。
我试过类似“排队退出”的方法:
connect(this, SIGNAL(signalFinish()),
&thread, SLOT(quit()),Qt::QueuedConnection);
...
void MyClass::finish()
{
emit signalFinish();
worker.disconnect(); // do not queue any more events
thread.wait();
}
但它不起作用。它将永远等待...
如何在事件循环将处理所有未决事件后停止 QThread
?
最佳答案
线程和 MyClass
实例都在同一个线程中 - 可能是主线程:
MyClass::MyClass() {
...
Q_ASSERT(this->thread() == thread.thread());
然而,您排队到工作对象的事件转到工作线程:
worker.moveToThread(&thread);
Q_ASSERT(worker.thread() == &thread);
Q_ASSERT(worker.thread() != thread.thread());
排队连接恰恰是错误的做法,因为一旦您在工作线程上等待,主线程的事件循环就不会运行,也不会向该线程发出更多事件。 quit
调用永远不会被传递,因为它是在主线程中传递的,但是主线程被阻塞了。
相反,利用 quit
作为线程安全方法的优势。从工作线程本身调用它:
// vvvvvvv thread context object for the call
connect(this, &MyClass::signalFinish, &worker, [this]{ thread.quit(); });
// the `quit()` will execute in `worker.thread()`
请注意,线程上下文对象是调用将在其 thread()
中执行的对象。它应该不是 QThread
例如,在大多数情况下!
当 signalFinish
发出时,携带上述仿函数的 QMetaCallEvent
将在工作线程的队列中排队,并将在任何现有调用(和其他)之后执行首先处理事件。
由于您在主线程中调用 finish
,您可能不想在线程上等待,因为这会阻塞 GUI 并使您的应用程序无响应。
因为看起来您正在将作业项提交给工作线程,所以您可能会更好地使用 QtConcurrent::run
将作业项提交给线程池,并执行所有线程管理你。参见 this answer一个完整的例子。参见 this answer和 that answer一些相关的花絮。
关于c++ - Qt 在另一个线程中为工作对象排队退出事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38223391/