Multithreading Qt线程在调用exit/quit后不会停止
我正试图结合线程更好地理解Qt信号和插槽。所以我尝试了这个最小的应用程序: foo.h:Multithreading Qt线程在调用exit/quit后不会停止,multithreading,qt,signals-slots,Multithreading,Qt,Signals Slots,我正试图结合线程更好地理解Qt信号和插槽。所以我尝试了这个最小的应用程序: foo.h: #include <QObject> class A : public QObject { Q_OBJECT public: void doit(); signals: void x(); }; class B : public QObject { Q_OBJECT public slots: void h(); }; #包括 A类:公共质量对象{ Q_对象 公众
#include <QObject>
class A : public QObject {
Q_OBJECT
public:
void doit();
signals:
void x();
};
class B : public QObject {
Q_OBJECT
public slots:
void h();
};
#包括
A类:公共质量对象{
Q_对象
公众:
void doit();
信号:
void x();
};
B类:公共质量对象{
Q_对象
公众时段:
空h();
};
foo.cpp:
#include "foo.h"
#include <QThread>
#include <QCoreApplication>
void B::h() {
qDebug("[%d] B::h() here!", (int) QThread::currentThreadId());
QCoreApplication::instance()->quit();
}
void A::doit() {
qDebug("[%d] emitting...", (int) QThread::currentThreadId());
emit x();
}
int main(int argc, char* argv[]) {
QCoreApplication app(argc, argv);
A a;
B b;
QObject::connect(&a, SIGNAL(x()), &b, SLOT(h()));
QThread t;
t.start();
b.moveToThread(&t);
a.doit();
t.wait();
return 0;
}
#包括“foo.h”
#包括
#包括
void B::h(){
qDebug(“[%d]B::h()此处!”,(int)QThread::currentThreadId());
QCoreApplication::instance()->quit();
}
void A::doit(){
qDebug(“[%d]发射…”,(int)QThread::currentThreadId());
发射x();
}
int main(int argc,char*argv[]){
QCore应用程序应用程序(argc、argv);
A A;
B B;
QObject::连接(&a,信号(x()),&b,插槽(h());
qt线程;
t、 start();
b、 移动到线程(&t);
a、 doit();
t、 等待();
返回0;
}
一切都很好,只是结尾的t.wait()永远不会返回。我的理解是调用quit()应该停止事件循环,这意味着exec()应该返回,run()也应该返回,线程执行应该停止。我遗漏了什么吗?您的代码似乎有很多地方出错
- 您不能调用
。这意味着没有主事件循环。将不会发出app.exec()
的A
信号x
- 默认情况下,Qt中的线程(至少从几年前开始)。然后启动一个线程调用
,然后启动事件循环。这是线程所在的位置,而不是Qthread::run()
t.wait()
的目的是什么?我相信你误用了它李>t.wait()
- (如果其他一切正常),在
中,您正在停止另一个线程的主线程。这就是你想做的吗B::h()
因此,我的第一个建议是添加
app.exec()
,看看它是如何工作的。解释你要做什么,并重写其他内容。因为QCoreApplication::quit()
未声明为线程安全方法,所以不能从其他线程调用它。您的应用程序可能会崩溃或获得未定义的行为(UB)
t.wait()
将永远不会返回,因为正在运行的线程一直在等待事件。要停止线程,必须调用QThread::quit()[slot]
如果要在工作完成后退出应用程序,则必须发出一个信号,该信号连接到QCoreApplication::quit()[static slot]
如果要在工作完成后停止工作线程,还必须发出一个连接到void QThread::quit()[slot]
补充:供进一步阅读
重要提示:您必须调用QCoreApplication::exec()
,以便能够在线程、排队连接之间使用信号和插槽机制
从Qt QThread文档:
每个QThread都可以有自己的事件循环。您可以启动事件循环
通过调用exec();您可以通过调用exit()或quit()来停止它。有
线程中的事件循环使连接来自线程的信号成为可能
使用名为排队的机制,将其他线程添加到此线程中的插槽
连接。它还可以使用需要
线程中的事件循环,如QTimer和QTcpSocket。注意,
但是,不可能在中使用任何小部件类
线
Qt::QueuedConnection的文档:
当控件返回到
接收器线程的事件循环。该插槽在中执行
接受者的线
方法的名称应该明确它们的用途。别担心,这不是生产代码!我发现假名字在短样本/测试代码中比人工描述的名字更有效。我同意UmNyobe。如果您使用的名称信息更丰富,那么阅读和理解示例代码就更容易了。例如,A::doit()->A::emitThreadStart()、void x()->startThread()、void h()->void quitApplication()。。。etcPerhaps你是对的,因为这最终是在一个公共论坛上发布的。我喜欢在我自己的测试中使用短名称,但这里可能不适合。t.start()调用run()方法,其默认实现调用exec()。正如我所说,信号的发射和接收都是正确的。wait()相当于pthread_join,或者文档中说的那样,所以我所做的就是等待线程完成。最后,你的最后一点是正确的。我不会停止线程事件循环。将该行更改为
QThread::currentThread()->quit()
可以实现这一目的。谢谢。exec()一直在运行,所以wait()没有效果。当然,这是真的,但是wait()的目的是等待exec()的结束,所以使用wait()本身并没有错;不停止正确的事件循环是错误的。因为我没有使用主事件循环,我真的需要app.exec()吗?似乎没有它一切都很好。你是对的。我没有停止正确的事件循环。不幸的是,巫统在你们面前指出了这一点,所以我不得不接受他们的答复。不过我对你的回答投了赞成票,因为它更清楚。谢谢。再想一想,我想我最好接受你的答案,因为另一个答案有很多错误信息,可能会让其他阅读它的人感到困惑。关于你添加的注意事项,在我的代码片段中,我没有调用QCoreApplication::exec()
,但信号/插槽确实有效。在我看来,QThread内部的事件循环就足够了,因为您没有将事件从线程发布到核心应用程序。尝试从连接到应用程序插槽的线程发出一个信号。我的理解是,我只需要一个事件循环,我想要有插槽。因为我不需要在我的应用程序的主线程中处理信号(我正在处理的是一个真正的信号,而不仅仅是这个简化的示例),工作线程中的一个事件循环就可以了。因此,简而言之,QCoreApplication::exec()
并不总是必需的