如果想要停止執行緒,QThread有個terminate()方法,但是這個方法並不建議使用,因為執行緒會直接停止正在進行的程式流程,無論現在是在流程的哪個位置,這會使得一些資源的善後工作無法完成,或因程式流程嘎然中止而導致不可預期的程式錯誤。
一個執行緒要停止,基本上就是執行完run()方法,讓它進入完成(Finished),簡單的說,如果您想要停止一個執行緒的執行,就要提供一個方式讓執行緒可以執行完run(),而這也是您自行實作執行緒停止的基本概念。
如果執行緒的run()方法中執行的是一個重複執行的迴圈,您可以提供一個flag來控制迴圈是否執行,藉此讓迴圈有可能終止、執行緒可以離開 run()方法以終止執行緒,以下面的實例來說,您提供一個bool的stopped變數:
- MessageThread.h
#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變數判斷是否繼續迴圈:
- MessageThread.cpp
#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:
- DemoDialog.h
#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()方法是沒有作用的:
- DemoDialog.cpp
#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:
- main.cpp
#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 模式。

