等待qthread终止的正确方法是什么?

时间:2018-10-01 17:57:07

标签: c++ qt qthread

我想知道创建QThread对象,终止它并等待主线程终止的正确方法。

我遇到的问题是QThread的wait()方法不会返回true(正如我认为的那样),并且一直阻塞直到超时到期为止。

我暂时通过在工作线程中的run()方法返回之前调用quit()方法来解决此问题,但我认为这样做不是正确的方法。

QT Documentation中说,如果线程已完成,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 :(得分:3)

线程不会仅仅因为您的RunProcess结束而停止运行。发送quit是关闭线程的正确方法。

也就是说,您还有两个与线程相关的问题:

  • 不能保证在TerminateProcess内部看到您的RunProcess标志。您应该使用QAtomicIntQSemaphore来确保工作线程看到标志更改。
  • 如果您要从外部(或在RunProcess中调用quit,则您的Terminate方法将阻止事件循环运行和关闭线程。您应该在QTimer的回调中“执行某些操作”,或者使用线程中断机制(调用方的QThread::requestInterruption和循环内的QThread::interruptionRequested)。

很大程度上取决于您的“执行操作”代码。如果那花了几分钟来计算Pi的位数而又不支持中断手段,那么与它外部的Qt事件循环的合作将无济于事。