Qt多線程-QThread


博客地址已更改,文章數量較多不便批量修改,若想訪問源文請到 coologic博客 查閱,網址:www.coologic.cn

如本文記錄地址為 techieliang.com/A/B/C/ 請改為 www.coologic.cn/A/B/C/ 即可查閱

 

版權聲明:若無來源注明, Techie亮博客文章均為原創。 轉載請以鏈接形式標明本文標題和地址:
本文標題:Qt多線程-QThread     本文地址: http://techieliang.com/2017/12/592/

1. 介紹

QThread是Qt提供的線程類,每一個QThread均可管理一個線程。

其具有兩種使用方式:1、繼承為QThread的子類;2、繼承為QObject的子類,並使用QObject::moveToThread將此對象移到線程中運行

QThread提供了如下基本函數:

線程啟動:start()運行一次

線程終止:terminate 終止線程,強制終止線程但會依據操作系統的調度策略,可能不是立即終止,最好用wait等待
quit退出線程,也可以調用exit,效果相同,會正常終止線程。

線程狀態查詢:isRunning是否正在運行,isFinished是否運行完成

線程狀態信號:started線程啟動時發出,finished線程結束時發出

其他:wait阻塞方式等待線程結束,調用此函數會將調用指令所在函數阻塞

建議對finished信號建立對應槽,實現線程結束后操作,而不是使用wait等待

更多詳細說明見官方文檔

1.1. 線程優先級

start函數有一個參數是線程優先級,此處使用的默認參數,若未設置也可以調用setPriority函數設置優先級,優先級分為以下幾類:

Constant Value Description
QThread::IdlePriority 0 scheduled only when no other threads are running.
QThread::LowestPriority 1 scheduled less often than LowPriority.
QThread::LowPriority 2 scheduled less often than NormalPriority.
QThread::NormalPriority 3 the default priority of the operating system.
QThread::HighPriority 4 scheduled more often than NormalPriority.
QThread::HighestPriority 5 scheduled more often than HighPriority.
QThread::TimeCriticalPriority 6 scheduled as often as possible.
QThread::InheritPriority 7 use the same priority as the creating thread. This is the default.

1.2. 線程休眠

sleep秒休眠、msleep毫秒休眠、usleep微秒休眠

2. 基本使用

2.1. 建立QThread子類法

  1. //mythread.h
  2. #pragma once
  3. #include <QThread>
  4. #include <QDebug>
  5. class MyThread : public QThread {
  6. Q_OBJECT
  7. protected:
  8. void run() {
  9. while(1) {
  10. num++;
  11. qDebug()<<num<<"thread start:"<<QThread::currentThreadId();
  12. msleep(500);
  13. qDebug()<<num<<"thread end:"<<QThread::currentThreadId();
  14. }
  15. }
  16. private:
  17. int num = 0;
  18. };
  19. //main.cpp
  20. #include <QCoreApplication>
  21. #include <QThread>
  22. #include <QDebug>
  23. #include "mythread.h"
  24. int main(int argc, char *argv[]) {
  25. QCoreApplication a(argc, argv);
  26. qDebug()<<"Main:"<<QThread::currentThreadId();
  27. MyThread m;
  28. m.start();
  29. QThread::sleep(5);
  30. m.terminate();
  31. m.wait();
  32. return 0;
  33. }

上述代碼測試了線程啟動、強制停止以及currentthreadid獲取當前線程id。

還可以使用currentthread獲取當前線程指針函數

2.2. moveToThread方法

  1. #pragma once
  2. #include <QThread>
  3. #include <QDebug>
  4. class MyThread : public QObject {
  5. Q_OBJECT
  6. public slots://注意要用槽函數
  7. void start() {
  8. qDebug()<<"thread end:"<<QThread::currentThreadId();
  9. }
  10. };
  11. #include <QCoreApplication>
  12. #include <QThread>
  13. #include <QDebug>
  14. #include "mythread.h"
  15. int main(int argc, char *argv[]) {
  16. QCoreApplication a(argc, argv);
  17. qDebug()<<"Main:"<<QThread::currentThreadId();
  18. QThread thread;
  19. MyThread m;
  20. m.moveToThread(&thread);
  21. QObject::connect(&thread,SIGNAL(started()),&m,SLOT(start()));
  22. thread.start();
  23. return 0;
  24. }

3. 線程同步

3.1. QMutex互斥量

幫助文檔

通過lock,unlock實現加鎖、解鎖

使用tryLock嘗試加鎖,會返回加鎖成功與否,同時可設置超時時間。

注意在lock以后,任意return前必須進行unlock,否則會造成死鎖

3.2. QMutexLocker

建立一個QMutex,通過QMutexLocker locker(&mutex);可以實現對mutex的自動處理,后續不需要自行進行lock和unlock,避免多個return情況下出現遺忘。

幫助文檔范例:

只是用QMutex的代碼:

  1. int complexFunction(int flag) {
  2. mutex.lock();
  3.  
  4. int retVal = 0;
  5.  
  6. switch (flag) {
  7. case 0:
  8. case 1:
  9. retVal = moreComplexFunction(flag);
  10. break;
  11. case 2: {
  12. int status = anotherFunction();
  13. if (status < 0) {
  14. mutex.unlock();
  15. return -2;
  16. }
  17. retVal = status + flag;
  18. }
  19. break;
  20. default:
  21. if (flag > 10) {
  22. mutex.unlock();
  23. return -1;
  24. }
  25. break;
  26. }
  27.  
  28. mutex.unlock();
  29. return retVal;
  30. }

使用QMutexLocker 代碼

  1. int complexFunction(int flag) {
  2. QMutexLocker locker(&mutex);
  3. int retVal = 0;
  4. switch (flag) {
  5. case 0:
  6. case 1:
  7. return moreComplexFunction(flag);
  8. case 2: {
  9. int status = anotherFunction();
  10. if (status < 0)
  11. return -2;
  12. retVal = status + flag;
  13. }
  14. break;
  15. default:
  16. if (flag > 10)
  17. return -1;
  18. break;
  19. }
  20. return retVal;
  21. }

3.3. QReadWriteLock

使用QMutex無論對變量進行何種操作(讀寫)均會鎖定變量,而實際上對於讀取變量值並不需要等待,可以多個線程同時讀取,此時使用QReadWriteLock可以實現多線程讀,單線程寫的操作。幫助文檔

范例:

  1. QReadWriteLock lock;
  2. void ReaderThread::run() {
  3. ...
  4. lock.lockForRead();
  5. read_file();
  6. lock.unlock();
  7. ...
  8. }
  9.  
  10. void WriterThread::run() {
  11. ...
  12. lock.lockForWrite();
  13. write_file();
  14. lock.unlock();
  15. ...
  16. }

3.4. QReadLocker和QWriteLocker

對於QReadWriteLock,qt也提供了類似於QMutexLocker的類,提供了對QReadWriteLock對象的托管,具體請見官方文檔:

QReadLocker???QWriteLocker

3.5. QSemaphore

Qt提供的信號量,相比於互斥量只能鎖定一次,信號量可以獲取多次,它可以用來保護一定數量的同種資源,可用於對緩沖區的管理。

  1. QSemaphore sem(5); // sem.available() == 5
  2. sem.acquire(3); // sem.available() == 2
  3. sem.acquire(2); // sem.available() == 0
  4. sem.release(5); // sem.available() == 5
  5. sem.release(5); // sem.available() == 10
  6. sem.tryAcquire(1); // sem.available() == 9, returns true
  7. sem.tryAcquire(250); // sem.available() == 9, returns false

 

4. 其他

4.1. 線程結束后自動銷毀的方法

connect(&thread, SIGNAL(finished()), &thread, SLOT(deleteLater()));

直接將線程結束的信號與deleteLater槽連接即可,deleteLater是QObject的槽函數

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM