Как правильно ждать завершения qthread? - PullRequest
0 голосов
/ 01 октября 2018

Я хочу знать правильный способ создания объекта QThread, его завершения и ожидания завершения в главном потоке.

Проблема, которую я получаю, состоит в том, что метод wait () QThread нене возвращает true (как мне кажется) и блокирует все время до истечения времени ожидания.

Я временно исправил это, вызвав метод quit (), прежде чем вернуться из метода run () в рабочем потоке, ноЯ думаю, что это не самый правильный способ сделать это.

В документации QT говорится, что wait () должна возвращать true, если поток завершил

(т.е. когда он возвращается из run ())

Я использую QT 5.9 и Linux.

У кого-нибудь была эта проблема?

MainWindow.h:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

# include <QMainWindow>
# include "Worker.h"

namespace Ui {
    class MainWindow;
}

class MainWindow : public QMainWindow {
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    void on_btnStart_clicked();
    void on_btnStop_clicked();

private:
    Worker *ProcWorker;
    QThread ProcessThread;
    Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H

MainWindow.cpp:

# include "MainWindow.h"
# include "ui_MainWindow.h"

MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent),  ui(new Ui::MainWindow) {
    ui->setupUi(this);

    this->ProcWorker = new Worker ();
    this->ProcWorker->moveToThread(&this->ProcessThread);
    QObject::connect (&this->ProcessThread, SIGNAL(started()), this->ProcWorker, SLOT(RunProcess()));
}

MainWindow::~MainWindow() {
    delete ui;
}

void MainWindow::on_btnStart_clicked() {
    this->ProcessThread.start ();
}

void MainWindow::on_btnStop_clicked() {
    this->ProcWorker->Terminate ();

    // It blocks until timeout has expired and return false.
    bool ret = this->ProcWorker->thread()->wait (1000000);
}

Worker.h:

#ifndef WORKER_H
#define WORKER_H

# include <QObject>
# include <QThread>

class Worker : public QObject {
Q_OBJECT
private:
    bool TerminateProcess;

public:
    Worker() {
        this->TerminateProcess = false;
    }

    void Terminate () {
        this->TerminateProcess = true;
    }

public slots:
    void RunProcess () {
        while (true) {
            QThread::msleep(100);
            if (this->TerminateProcess) {
                break;
            }

            // Do something
        }

        // I need to add this to get wait() works
        //this->thread()->quit ();
    }
};

#endif

1 Ответ

0 голосов
/ 01 октября 2018

Поток не останавливается просто потому, что ваш RunProcess заканчивается.Отправка quit является правильным способом завершения потока.

Тем не менее, у вас есть две другие проблемы, связанные с потоками:

  • Ваш флаг TerminateProcess не являетсягарантированно будет видно внутри RunProcess.Вы должны использовать QAtomicInt или QSemaphore, чтобы убедиться, что рабочий поток видит изменение флага.
  • Ваш метод RunProcess блокирует запуск цикла обработки и отключение потока, если вы вызываете quit снаружи (или в Terminate).Вы должны либо «сделать что-то» в обратном вызове от QTimer, либо использовать механику прерывания потока (QThread::requestInterruption от вызывающей стороны и QThread::interruptionRequested внутри цикла).

Многое зависит отВаш код "Сделай что-нибудь".Если это тратит минуты на вычисление цифр числа Пи без поддержки средства прерывания, никакое сотрудничество с циклом событий Qt вне его не спасет вас.

...