Qt-поток не останавливается после вызова exit/quit

5 Elektito [2012-02-20 11:26:00]

Я пытаюсь найти лучшее понимание сигналов и слотов 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() должен возвратиться и поэтому должен работать(), и выполнение потока должно прекратиться. Я что-то пропустил?

multithreading qt signals-slots


2 ответа


10 Решение Dmitriy [2012-02-20 12:34:00]

QCoreApplication::quit () не указывается как поточно-безопасный метод, поэтому вы не можете вызвать его из другого потока. Приложение может сбой или получить поведение undefined (UB).

t.wait() никогда не вернется, потому что текущий поток постоянно ждет событий. Чтобы остановить поток, вы должны вызвать QThread::quit () [slot]

Если вы хотите выйти из приложения после завершения работы, вы должны испустить сигнал, который подключен к QCoreApplication::quit () [static slot]

Если вы хотите остановить рабочий поток после завершения работы, вам также необходимо исправить сигнал, подключенный к void QThread::quit () [slot]

Добавлено: Темы, события и QObjects для дальнейшего чтения

Важное замечание: Вы должны позвонить QCoreApplication::exec(), чтобы иметь возможность использовать механизм сигнала и слота между потоками, очереди в очереди.

Из Qt QThread doc:

Каждый QThread может иметь свой собственный цикл событий. Вы можете запустить цикл событий путем вызова exec(); вы можете остановить его, вызвав exit() или quit(). имеющий цикл событий в потоке позволяет подключать сигналы от другие потоки в слоты в этом потоке, используя механизм под названием в очереди соединения. Это также позволяет использовать классы, требующие цикл событий, такой как QTimer и QTcpSocket, в потоке. Заметка, однако, что нельзя использовать какие-либо классы виджетов в нить.

Doc для Qt:: QueuedConnection:

Слот вызывается, когда управление возвращается к цикл событий в потоке приемника. Слот выполнен в поток приемника.


2 UmNyobe [2012-02-20 12:19:00]

Кажется, что с вашим кодом есть много чего.

Итак, мой первый совет - добавить app.exec(), посмотреть, как он себя ведет. Объясните, что вы пытаетесь сделать, и перепишите что-то еще. Поскольку вы делаете это неправильно