先建立一個工程吧, 具體步驟前面講過不少次了, 就再也不細說了。框架
而後在Header文件夾下建立添加一個頭文件, 右鍵Headers -> Add New... -> C++ -> C++ Header File -> Choose函數
隨便起個名字, 好比mythread, 而後點Next->Finish。ui
在mythread.h中包含QThread
頭文件:操作系統
按住Ctrl鍵, 點擊QThread
, 再按住Ctrl鍵點擊qthread.h
進入到qthread.h文件, 源碼就在這裏了, 隨便看看就好。哪裏不懂就鼠標點一下不懂的地方, 而後按F1, 會跳轉到相應的幫助文檔,裏面講得很詳細, 裏面的英文也比較簡單。線程
void start(Priority = InheritPriority);
經過調用start()
方法來啓動線程,該方法會調用run()
函數(能夠看到QThread中run()
爲虛函數, 須要咱們來重載)。code
run()
函數可調用exec()
讓該線程進入事件循環。orm
Priority爲線程優先級(下面會講)。對象
void exit(int retcode = 0);
void quit();
void terminate();
void requestInterruption();
+ bool isInterruptionRequested();
requestInterruption
用於請求線程進行中斷。isInterruptionRequested
返回true/false, 用於判斷是否有終止線程的請求。bool wait(unsigned long time = ULONG_MAX);
static void sleep(unsigned long);
static void msleep(unsigned long);
static void usleep(unsigned long);
bool isFinished() const;
bool isRunning() const;
bool isInterruptionRequested() const;
requestInterruption()
發出。void setPriority(Priority priority);
blog
用於設置正在運行的線程的優先級, 若是線程未運行, 則該返回不會執行任何操做並馬上返回。可用start(priority)
啓動帶優先級的線程。
指定的優先級是否生效取決於操做系統的調度, 若是是不支持線程優先級的系統上, 優先級的設置將被忽略。
優先級能夠設置爲QThread::Priority內除InheritPriortyd的任何值:
QThread::Priority枚舉元素 | 值 | 描述 |
---|---|---|
QThread::IdlePriority | 0 | 沒有其它線程運行時才調度 |
QThread::LowestPriority | 1 | 比LowPriority調度頻率低 |
QThread::LowPriority | 2 | 比NormalPriority調度頻率低 |
QThread::NormalPriority | 3 | 操做系統的默認優先級 |
QThread::HighPriority | 4 | 比NormalPriority調度頻繁 |
QThread::HighestPriority | 5 | 比HighPriority調度頻繁 |
QThread::TimeCriticalPriority | 6 | 儘量頻繁的調度 |
QThread::InheritPriority | 7 | 使用和建立線程一樣的優先級(這是默認值) |
void started(QPrivateSignal);
start
後, 執行run
前發出該信號。void finished(QPrivateSignal);
在mythread.h中定義MyThread
類, 並繼承QThread
, 而後把框架寫好:
#ifndef MYTHREAD_H #define MYTHREAD_H #include <QThread> class MyThread : public QThread { Q_OBJECT public: MyThread(); private: protected: void run(); signals: public slots: }; #endif // MYTHREAD_H
新建一個C++ Source File, 命名爲mythread.cpp
mythread.cpp代碼以下, run()
函數中咱們讓它每隔1秒打印一次字符串:
#include "mythread.h" // 構造函數 MyThread::MyThread() { } void MyThread::run() { while (!isInterruptionRequested()) { qDebug() << "Running..."; sleep(1); } qDebug() << "Get Interruption Request, I'll exit."; }
由於用到了qDebug()
, 別忘了在mythread.h中添加<QDebug>頭文件:
#include <QDebug>
在mainwindow.h中添加頭文件和聲明變量:
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include "mythread.h" // 添加頭文件 class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = 0); ~MainWindow(); private: MyThread *my_thread; // 聲明變量 }; #endif // MAINWINDOW_H
在mainwindow.cpp中開啓和結束線程:
#include "mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { my_thread = new MyThread; // 實例化 my_thread->start(); // 開啓線程 // 主線程阻塞5秒 QDateTime start = QDateTime::currentDateTime(); QDateTime now; do { now = QDateTime::currentDateTime(); } while(start.secsTo(now) < 5); // 關閉線程 my_thread->requestInterruption(); my_thread->wait(); } MainWindow::~MainWindow() { }
由於用到了<QDateTime>, 別忘了在mainwindow.h中添加頭文件:
#include <QDateTime>
運行結果:
能夠看到主線程被阻塞了5秒, 以後才彈出窗口。可是在主線程阻塞期間, 咱們的my_thread線程仍在運行, 直到線程被關閉。
上面咱們結束線程使用的是requestInterruption()
和isInterruptionRequested()
, 這是Qt5新增的, 那麼Qt4要如何結束線程呢?
bool is_stopped
初值賦爲false;stop()
, 當調用my_thread->stop();
時將is_stopped
改成true;run()
中判斷, 若是is_stopped
爲false
線程繼續執行, 若是爲true
線程退出; 別忘了退出前再將is_stopped
改成false
, 否則線程無法再次開啓了。代碼以下:
mythread.h
#ifndef MYTHREAD_H #define MYTHREAD_H #include <QThread> #include <QDebug> class MyThread : public QThread { Q_OBJECT public: MyThread(); void stop(); // 添加stop()方法 private: volatile bool is_stopped; // 添加標識變量 protected: void run(); signals: public slots: }; #endif // MYTHREAD_H
mythread.cpp
#include "mythread.h" // 構造函數 MyThread::MyThread() { is_stopped = false; // 初始化標識變量 } void MyThread::run() { while (!is_stopped) // 更改判斷條件 { qDebug() << "Running..."; sleep(1); } qDebug() << "is_stopped is true, I'll exit."; is_stopped = false; // 重置變量值 } // 關閉線程 void MyThread::stop() { is_stopped = true; }
mainwindow.cpp
#include "mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { my_thread = new MyThread; // 實例化 my_thread->start(); // 開啓線程 // 主線程阻塞5秒 QDateTime start = QDateTime::currentDateTime(); QDateTime now; do { now = QDateTime::currentDateTime(); } while(start.secsTo(now) < 5); // 關閉線程 my_thread->stop(); // 用本身定義的方法關閉線程 my_thread->wait(); } MainWindow::~MainWindow() { }
看例子, 咱們修改一下run()
函數和關閉線程部分的代碼:
mythread.cpp
void MyThread::run() { while (!isInterruptionRequested()) { qDebug() << "Running..."; sleep(1); } qDebug() << "子線程: 我只退出了while循環, 沒有真正結束"; exec(); // 事件循環 qDebug() << "子線程: 我真的要結束了"; }
mainwindow.cpp
// 關閉線程 my_thread->requestInterruption(); qDebug() << "主線程: 發起中斷請求"; my_thread->wait(3000); my_thread->quit(); qDebug() << "主線程: 請求退出線程的事件循環"; my_thread->wait(); // 等待線程結束
運行結果:
在主進程requestInterruption()
後, 只是使得isInterruptionRequested()
變爲true, 退出了while循環, 在主線程中調用wait(3000)
, 並無馬上返回, 而是3秒超時後才返回, 說明子線程沒有真正結束, 而是執行到了exec()
處進行事件循環。經過調用quit()
或exit()
來結束子線程的事件循環, 子線程才真的結束了。
QObject
, 把要在線程中執行的工做做爲類的槽函數:dowork.h
#ifndef DOWORK_H #define DOWORK_H #include <QObject> #include <QDateTime> #include <QDebug> class DoWork : public QObject { Q_OBJECT public: explicit DoWork(QObject *parent = nullptr); public slots: void do_something(); }; #endif // DOWORK_H
dowork.cpp
#include "dowork.h" DoWork::DoWork(QObject *parent) : QObject(parent) { } void DoWork::do_something() { int a = 5; while(a--) { qDebug() << "Doing something ..."; QDateTime start = QDateTime::currentDateTime(); QDateTime now; do { now = QDateTime::currentDateTime(); } while(start.secsTo(now) < 1); } qDebug() << "Done"; }
work1
對象移到新線程下:mainwindow.h
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QThread> #include "dowork.h" class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = 0); ~MainWindow(); private: DoWork *work1; // 自定義的類 QThread *new_thread; // 新線程 }; #endif // MAINWINDOW_H
mainwindow.cpp
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { // 實例化 work1 = new DoWork; new_thread = new QThread; work1->moveToThread(new_thread); // 搬到線程下 }
綁定線程啓動後要作的工做:
connect(new_thread, &QThread::started, work1, &DoWork::do_something);
使用moveToThread
的方法很是靈活, 你不必定要用&QThread::started
來觸發do_something
, 也可使用自定義的信號, 爲了例程簡單明瞭, 這裏不舉例了。
啓動線程
new_thread->start();
爲了更安全, 線程結束後別忘了釋放資源:
connect(new_thread, &QThread::finished, work1, &QObject::deleteLater);
MainWindow::~MainWindow() { new_thread->requestInterruption(); new_thread->quit(); new_thread->wait(); }
mainwindow.cpp
#include "mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { // 實例化 work1 = new DoWork; new_thread = new QThread; work1->moveToThread(new_thread); // 搬到線程下 connect(new_thread, &QThread::started, work1, &DoWork::do_something); connect(new_thread, &QThread::finished, work1, &QObject::deleteLater); new_thread->start(); } MainWindow::~MainWindow() { new_thread->requestInterruption(); new_thread->quit(); new_thread->wait(); }
運行結果以下: