简体   繁体   中英

what's the correct way to wait for qthread termination?

I want to know the correct way to create a QThread object, terminate it and wait for the termination in the main thread.

The problem I'm getting is that the wait() method of QThread doesn't return true (as i think it has) and blocks allways until the timeout has expired.

I temporally fixed this by calling quit() method before returning from the run() method in the worker thread, but I think it shoudn't be the correct way to do that.

In the QT Documentation says that wait() should return true if the thread has finished

(ie when it returns from run())

I'm using QT 5.9 and Linux.

Do anyone had this problem?

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

The thread does not stop running simply because your RunProcess ends. Sending a quit is a correct means of shutting down the thread.

That said, you have two other problems related to the threading:

  • Your TerminateProcess flag is not guaranteed to be seen inside RunProcess . You should use a QAtomicInt or a QSemaphore to ensure the worker thread sees the flag change.
  • Your RunProcess method blocks the event loop from running and shutting down the thread if you were to call quit from the outside (or in Terminate ). You should either "do something" in the callback from a QTimer or use the thread interruption mechanic ( QThread::requestInterruption from the caller and QThread::interruptionRequested inside the loop).

A lot depends on your "Do something" code. If that spends minutes calculating digits of Pi without supporting a means of interruption, no amount of cooperation with the Qt event loop outside of it will save you.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM