如果想要停止執行緒,QThread有個terminate()方法,但是這個方法並不建議使用,因為執行緒會直接停止正在進行的程式流程,無論現在是在流程的哪個位置,這會使得一些資源的善後工作無法完成,或因程式流程嘎然中止而導致不可預期的程式錯誤。
一個執行緒要停止,基本上就是執行完run()方法,讓它進入完成(Finished),簡單的說,如果您想要停止一個執行緒的執行,就要提供一個方式讓執行緒可以執行完run(),而這也是您自行實作執行緒停止的基本概念。
如果執行緒的run()方法中執行的是一個重複執行的迴圈,您可以提供一個flag來控制迴圈是否執行,藉此讓迴圈有可能終止、執行緒可以離開 run()方法以終止執行緒,以下面的實例來說,您提供一個bool的stopped變數:
#ifndef MESSAGETHREAD_H #define MESSAGETHREAD_H
#include <QThread>
class MessageThread : public QThread { Q_OBJECT public: MessageThread(); void setMessage(const QString &message); void stop(); protected: void run(); private: QString msg; bool stopped; };
#endif
在這個類別中,您可以藉由setMessage()設定要顯示的訊息文字,在run()方法中,while迴圈由stopped變數判斷是否繼續迴圈:
#include "MessageThread.h" #include <iostream> using namespace std;
MessageThread::MessageThread() { this->stopped = false; }
void MessageThread::setMessage(const QString &msg) { this->msg = msg; }
void MessageThread::stop() { stopped = true; }
void MessageThread::run() { while (!stopped) { cerr << qPrintable(msg) << endl; QThread::sleep(1); } }
若要停止執行緒,可以呼叫stop()方法,這會使得stopped變數設為true,而使得while迴圈可以結束,從而可以讓執行緒執行完run()而進入完成。
要判斷執行緒是否正在執行,可以使用QThread的isRunning()方法,要判斷執行緒是否完成,可以使用QThread的isFinished(),以下可以寫個簡單的程式來使用以上的MessageThread:
#ifndef DEMODIALOG_H #define DEMODIALOG_H
#include "MessageThread.h" #include <QDialog>
class QWidget; class QPushButton; class QCloseEvent;
class DemoDialog : public QDialog { Q_OBJECT public: DemoDialog(QWidget *parent = 0);
public slots: void startOrStop(); protected: void closeEvent(QCloseEvent *event);
private: QPushButton *btn; MessageThread thread; };
#endif
程式中會有個按鈕,按下後可以啟動另一個執行緒,並設定按鈕文字為「Stop」,若再按下,則會呼叫
MessageThread的stop()停止執行緒,此時設定按鈕文字為「Finished」,並設定按鈕為不可按下,執行緒完成後,再呼叫其
start()方法是沒有作用的:
#include "DemoDialog.h" #include "MessageThread.h" #include <QPushButton> #include <QVBoxLayout> #include <QCloseEvent>
DemoDialog::DemoDialog(QWidget *parent) : QDialog(parent) { btn = new QPushButton("Start", this); QVBoxLayout *layout = new QVBoxLayout; layout->addWidget(btn); this->setLayout(layout); thread.setMessage("message...."); connect(btn, SIGNAL(clicked()), this, SLOT(startOrStop())); }
void DemoDialog::startOrStop() { if(thread.isRunning()) { thread.stop(); btn->setText("Finished"); btn->setEnabled(false); } else { thread.start(); btn->setText("Stop"); } }
void DemoDialog::closeEvent(QCloseEvent *event) { thread.stop(); thread.wait(); event->accept(); }
QThread的wait()方法,可以確實的等待執行緒完成,再進行接下來的動作,您也可以指定wait()的時間,在時間到時,無論如何就進行接下來的動作。
可以撰寫以下的簡單程式來使用DemoDialog:
#include <QApplication> #include "DemoDialog.h"
int main(int argc, char *argv[]) { QApplication app(argc, argv); DemoDialog *demoDialog = new DemoDialog; demoDialog->setWindowTitle("Thread Demo"); demoDialog->resize(200, 50); demoDialog->show(); return app.exec(); }
有關於執行緒的終止,還可以參考 Two-phase Termination 模式。
|