Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Qt thread does not stop after calling exit/quit

I'm trying to find a better understanding of Qt signals and slots in conjunction with threads. So I tried this minimal application:

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;
}

Everything is fine, only the t.wait() at the end never returns. My understanding is calling quit() should stop the event loop, which means exec() should return and so should run() and thread execution should stop. Am I missing something?

like image 530
Elektito Avatar asked Feb 20 '12 08:02

Elektito


People also ask

How do you stop a thread in Qt?

Calling QThread::quit() posts a termination message to this queue. When QThread::exec() will read it, it will stop further processing of events, exit infinite loop and gently terminate the thread.

What is event loop in Qt?

Qt's event loop starts the moment the underlying application's exec() function gets called. Once started, the loop repeatedly checks for something to happen in the system, such as user-input through keyboard/mouse.

How do you wait for a signal in Qt?

Starting in Qt 5.0, QSignalSpy offers a wait method. You hook it up to a signal and wait() will block until the signal fires.


Video Answer


2 Answers

QCoreApplication::quit () is not stated as thread-safe method so you can't call it from another thread. Your application can crash or get an undefined behavior(UB).

t.wait() will never return because the running thread is constantly waiting for events. To stop the thread you must call QThread::quit () [slot]

If you want to quit the application after the work is done you have to emit a signal, which is connected to QCoreApplication::quit () [static slot]

If you want to stop the worker thread after the work is done you also have to emit a signal, connected to void QThread::quit () [slot]

Added: Threads, Events and QObjects for further reading

Important notice: You must call QCoreApplication::exec() in order to be able to use signal & slot mechanism between threads, queued connections.

From Qt QThread doc:

Each QThread can have its own event loop. You can start the event loop by calling exec(); you can stop it by calling exit() or quit(). Having an event loop in a thread makes it possible to connect signals from other threads to slots in this thread, using a mechanism called queued connections. It also makes it possible to use classes that require the event loop, such as QTimer and QTcpSocket, in the thread. Note, however, that it is not possible to use any widget classes in the thread.

Doc for Qt::QueuedConnection:

The slot is invoked when control returns to the event loop of the receiver's thread. The slot is executed in the receiver's thread.

like image 101
Dmitriy Avatar answered Oct 15 '22 09:10

Dmitriy


It seems that there are many things wrong with your code.

  • You don't call app.exec(). Meaning that there is no main event loop. The x signal of A will not be emitted.
  • By default, a thread has it's own even loop in Qt (at least since few years). Then starting a thread call Qthread::run(), and the event loop is started. That's where your thread is, not in t.wait().
  • What is the purpose of t.wait()? I believe you are misusing it.
  • (If everything else was fine), in B::h() you are stopping the main thread from the other thread. Is that what you wanted to do?

So my first advice will be to add app.exec(), see how it behaves. Explain what your are trying to do, and rewrite something else. Because you're doing it wrong

like image 37
UmNyobe Avatar answered Oct 15 '22 10:10

UmNyobe