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

时间:2012-02-20 08:26:02

标签: 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();
};

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()并且线程执行应该停止。我错过了什么吗?

2 个答案:

答案 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}}信号将不会被发出。
  • 默认情况下,Qt中的一个帖子has it's own even loop(至少从几年开始)。然后启动线程调用A,并启动事件循环。这就是你的主题,而不是Qthread::run()
  • t.wait()的目的是什么?我相信你在滥用它。
  • (如果其他一切都很好),在t.wait()中,您将从另一个线程停止主线程。那是你想做的吗?

所以我的第一个建议是添加B::h(),看看它的行为方式。解释你正在尝试做什么,并重写其他内容。因为you're doing it wrong