等待 qthread 终止的正确方法是什么?
what's the correct way to wait for qthread termination?
我想知道创建QThread对象的正确方法,终止它并在主线程中等待终止。
我遇到的问题是 QThread 的 wait() 方法不 return 正确(正如我认为的那样)并且一直阻塞直到超时到期。
我通过在工作线程中从 运行() 方法 returning 之前调用 quit() 方法暂时修复了这个问题,但我认为这不应该是正确的做法那。
在 QT Documentation 中说如果线程已经完成,wait() 应该 return true
(i.e. when it returns from 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
线程不会因为您的 RunProcess
结束而停止 运行。发送 quit
是关闭线程的正确方法。
也就是说,您还有两个与线程相关的问题:
- 不能保证在
RunProcess
中看到您的 TerminateProcess
标志。您应该使用 QAtomicInt
或 QSemaphore
来确保工作线程看到标志更改。
- 如果您要从外部(或在
Terminate
中)调用 quit
,您的 RunProcess
方法会阻止 运行 的事件循环并关闭线程。您应该在 QTimer
的回调中 "do something" 或使用线程中断机制(来自调用者的 QThread::requestInterruption
和循环内的 QThread::interruptionRequested
)。
很大程度上取决于您的 "Do something" 代码。如果在不支持中断方式的情况下花几分钟计算 Pi 的数字,那么与它之外的 Qt 事件循环再多的合作也救不了你。
我想知道创建QThread对象的正确方法,终止它并在主线程中等待终止。
我遇到的问题是 QThread 的 wait() 方法不 return 正确(正如我认为的那样)并且一直阻塞直到超时到期。
我通过在工作线程中从 运行() 方法 returning 之前调用 quit() 方法暂时修复了这个问题,但我认为这不应该是正确的做法那。
在 QT Documentation 中说如果线程已经完成,wait() 应该 return true
(i.e. when it returns from 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
线程不会因为您的 RunProcess
结束而停止 运行。发送 quit
是关闭线程的正确方法。
也就是说,您还有两个与线程相关的问题:
- 不能保证在
RunProcess
中看到您的TerminateProcess
标志。您应该使用QAtomicInt
或QSemaphore
来确保工作线程看到标志更改。 - 如果您要从外部(或在
Terminate
中)调用quit
,您的RunProcess
方法会阻止 运行 的事件循环并关闭线程。您应该在QTimer
的回调中 "do something" 或使用线程中断机制(来自调用者的QThread::requestInterruption
和循环内的QThread::interruptionRequested
)。
很大程度上取决于您的 "Do something" 代码。如果在不支持中断方式的情况下花几分钟计算 Pi 的数字,那么与它之外的 Qt 事件循环再多的合作也救不了你。