[英]Qt queued exit event for worker object in another thread
MyClass
对象有一个工作器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对象的事件将进入worker线程:
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
可能会更好地为您提供服务,该程序将工作项提交给线程池,并为您执行所有线程管理。 有关完整示例,请参见此答案 。 请参阅此答案以及该答案的一些相关花絮。
您可以使用QThread :: exec()调用在事件循环中运行线程。 线程将运行它,直到您通过调用QThread :: exit()告诉线程退出。 因此,一些示例代码如下所示:
void DownloadWorker::run()
{
DownloadManager* pDownloadManager = new DownloadManager(this);
connect(pDownloadManager, SIGNAL(finished()), SLOT(exit()));
connect(pDownloadManager, SIGNAL(error()), SLOT(exit()));
pDownloadManager->download();
exec();
}
这将确保您在发出DownloadManager的“ finished()”信号之前不会退出线程。
注意:这里我举了一个示例来说明如何解决您的问题,但我不知道您的整个应用程序代码。 这意味着不能保证此代码是线程安全的和一致的。 您需要自己照顾互斥锁和所有正确的同步。 要非常小心 ! 使用这样的“低级”线程API可以使您更好地理解multithereading。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.