我正在尝试与线程一起更好地理解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();
};
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;
}
一切都很好,只有最后的t.wait()永远不会返回。我的理解是调用quit()应该停止事件循环,这意味着exec()应该返回,所以应该run()并且线程执行应该停止。我错过了什么吗?
答案 0 :(得分:10)
QCoreApplication::quit ()
未声明为线程安全方法,因此您无法从另一个线程调用它。您的应用程序可能崩溃或获得未定义的行为(UB)。
t.wait()
永远不会返回,因为正在运行的线程一直在等待事件。要停止该主题,您必须致电QThread::quit () [slot]
如果要在完成工作后退出应用程序,则必须发出信号,该信号已连接到QCoreApplication::quit () [static slot]
如果你想在工作完成后停止工作线程,你还必须发出信号,连接到void QThread::quit () [slot]
已添加:Threads, Events and QObjects以供进一步阅读
重要提示:您必须致电QCoreApplication::exec()
才能使用信号&amp;线程之间的插槽机制,排队连接。
来自Qt QThread doc:
每个QThread都有自己的事件循环。您可以启动事件循环 通过调用exec();你可以通过调用exit()或quit()来停止它。有 线程中的事件循环使得连接信号成为可能 使用名为排队的机制的其他线程到此线程中的插槽 连接即可。它还可以使用需要的类 线程中的事件循环,例如QTimer和QTcpSocket。注意, 但是,不可能在中使用任何窗口小部件类 线程。
Doc for Qt :: QueuedConnection:
当控制返回时,调用插槽 接收者线程的事件循环。插槽在中执行 接收者的主题。
答案 1 :(得分:2)
您的代码似乎有很多问题。
app.exec()
。意味着没有主事件循环。 x
的{{1}}信号将不会被发出。A
,并启动事件循环。这就是你的主题,而不是Qthread::run()
。t.wait()
的目的是什么?我相信你在滥用它。 t.wait()
中,您将从另一个线程停止主线程。那是你想做的吗?所以我的第一个建议是添加B::h()
,看看它的行为方式。解释你正在尝试做什么,并重写其他内容。因为you're doing it wrong