Multithreading Qt线程在调用exit/quit后不会停止

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_对象 公众

我正试图结合线程更好地理解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_对象
公众:
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()
并不总是必需的