Qt多線程-QThreadPool線程池與QRunnable


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

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

 

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

1. 介紹

線程的創建及銷毀需要與系統交互,會產生很大的開銷。若需要頻繁的創建線程建議使用線程池,有線程池維護一定數量的線程,當需要進行多線程運算時將運算函數傳遞給線程池即可。線程池會根據可用線程進行任務安排。

2. QThreadPool

相關幫助文檔:QThreadPool

此類為Qt提供的線程池函數,使用此類只需要配置線程池的最大線程數量、線程長時間不使用的過期時間等參數,不需要進行QThread相關的操作。

此類有兩種使用方式:全局線程池和局部線程池。下面首先介紹兩種類型后續介紹類提供的方法

2.1. 基本操作函數

  1. int activeThreadCount() const //當前的活動線程數量
  2. void clear()//清除所有當前排隊但未開始運行的任務
  3. int expiryTimeout() const//線程長時間未使用將會自動退出節約資源,此函數返回等待時間
  4. int maxThreadCount() const//線程池可維護的最大線程數量
  5. void releaseThread()//釋放被保留的線程
  6. void reserveThread()//保留線程,此線程將不會占用最大線程數量,從而可能會引起當前活動線程數量大於最大線程數量的情況
  7. void setExpiryTimeout(int expiryTimeout)//設置線程回收的等待時間
  8. void setMaxThreadCount(int maxThreadCount)//設置最大線程數量
  9. void setStackSize(uint stackSize)//此屬性包含線程池工作線程的堆棧大小。
  10. uint stackSize() const//堆大小
  11. void start(QRunnable *runnable, int priority = 0)//加入一個運算到隊列,注意start不一定立刻啟動,只是插入到隊列,排到了才會開始運行。需要傳入QRunnable ,后續介紹
  12. bool tryStart(QRunnable *runnable)//嘗試啟動一個
  13. bool tryTake(QRunnable *runnable)//刪除隊列中的一個QRunnable,若當前QRunnable 未啟動則返回成功,正在運行則返回失敗
  14. bool waitForDone(int?<i>msecs</i>?=?-1)//等待所有線程運行結束並退出,參數為等待時間-1表示一直等待到最后一個線程退出

QThread::idealThreadCount函數,會根據當前設備的硬件情況給出一個線程數量,而maxThreadCount的默認值就是此值。

setStackSize

只有在線程池創建新線程時才使用該屬性的值。更改它對已經創建或運行的線程沒有影響。默認值是0,這使得qthread使用操作系統默認的堆棧大小。

The value of the property is only used when the thread pool creates new threads. Changing it has no effect for already created or running threads.

The default value is 0, which makes QThread use the operating system default stack size.

maxThreadCount? reserveThread? activeThreadCount

由於reserveThread 后的線程不計入線程數量,因此可能出現activeThreadCount>maxThreadCount? 情況

Note: It is possible for this function to return a value that is greater than maxThreadCount(). See reserveThread() for more details.

2.2. start tryStart tryTake

對於start,傳入的是QRunnable對象指針,傳入后線程池會調用QRunnable的autoDelete() 函數,若返回true,則當此運算完成后自動釋放內容,不需要后續主動判斷是否運算完成並釋放空間。

對於tryTake,若返回成功,不會自動釋放內容,而是需要調用方主動釋放,無論autodelete返回值是什么。返回false自然也不會自動delete

Attempts to remove the specified runnable from the queue if it is not yet started. If the runnable had not been started, returns true, and ownership of runnable is transferred to the caller (even when runnable->autoDelete() == true). Otherwise returns false.

Note: If runnable->autoDelete() == true, this function may remove the wrong runnable. This is known as the ABA problem: the original runnable may already have executed and has since been deleted. The memory is re-used for another runnable, which then gets removed instead of the intended one. For this reason, we recommend calling this function only for runnables that are not auto-deleting.

對於tryStart,若返回成功,等同於start,若false,則不會自動delete

注意,對於autoDelete必須在調用state/trytake之前進行修改,不要再調用以后修改,否則結果不可預測

Note that changing the auto-deletion on runnable after calling this function results in undefined behavior.

QRunnable的autoDelete默認返回true,若需要更改需要調用setAutoDelete進行更改

2.3. 全局線程池

QThreadPool提供了一個靜態函數,globalInstance(),使用此方法可獲取一個當前進程的全局線程池,可在多個類中共同使用一個線程池。

2.4. 局部線程池

和常規類的使用相同,可以通過? QThreadPool pool;的方式建立一個局部線程池,並由當前類維護,可保證此線程池僅供當前類應用

3. QRunnable

線程池每一個需要運行的任務均需要作為QRunnable的子類,並重寫其run函數,幫助文檔:http://doc.qt.io/qt-5/qrunnable.html

QRunnable只有run、autodelete、setautodelete這三個關鍵函數。

run內重寫需要運算的內容。

autodelete用來標識是否在運行結束后自動由線程池釋放空間,具體說明見上述“QThreadPool-基本操作函數-start tryStart tryTake”

4. 范例

4.1. 簡單使用范例

  1. #include <QCoreApplication>
  2. #include <QThreadPool>
  3. #include <QThread>
  4. #include <QRunnable>
  5. #include <QDebug>
  6. class MyRun : public QRunnable {
  7. public:
  8. void run() {
  9. int i=3;
  10. while(i) {
  11. i--;
  12. qDebug()<<"thread start:"<<QThread::currentThreadId();
  13. QThread::msleep(500);
  14. }
  15. }
  16. };
  17. int main(int argc, char *argv[]) {
  18. QCoreApplication a(argc, argv);
  19. qDebug()<<"Main:"<<QThread::currentThreadId();
  20. QThreadPool m;
  21. MyRun *run=new MyRun;
  22. if(!run->autoDelete()) {
  23. qDebug()<<"QRunnable's autoDelete default value is not true";
  24. run->setAutoDelete(true);
  25. }
  26. qDebug()<<m.maxThreadCount()<<m.expiryTimeout();
  27. qDebug()<<m.activeThreadCount();
  28. m.start(run);
  29. qDebug()<<m.activeThreadCount();
  30. m.waitForDone();
  31. qDebug()<<m.activeThreadCount();
  32. return 0;
  33. }

結果:

  1. Main: 0xffc
  2. 4 30000
  3. 0
  4. 1
  5. thread start: 0x7e4
  6. thread start: 0x7e4
  7. thread start: 0x7e4
  8. 0

4.2. 全局線程池和局部線程池對比

  1. #include <QCoreApplication>
  2. #include <QThreadPool>
  3. #include <QThread>
  4. #include <QRunnable>
  5. #include <QDebug>
  6. class MyRun : public QRunnable {
  7. public:
  8. void run() {
  9. int i=3;
  10. while(i) {
  11. i--;
  12. qDebug()<<"thread start:"<<QThread::currentThreadId();
  13. QThread::msleep(500);
  14. }
  15. }
  16. };
  17. int main(int argc, char *argv[]) {
  18. QCoreApplication a(argc, argv);
  19. qDebug()<<"Main:"<<QThread::currentThreadId();
  20. QThreadPool pool;
  21. QThreadPool *global_pool = QThreadPool::globalInstance();
  22. MyRun *run=new MyRun;
  23. if(!run->autoDelete()) {
  24. qDebug()<<"QRunnable's autoDelete default value is not true";
  25. run->setAutoDelete(true);
  26. }
  27. pool.setMaxThreadCount(2);//修改了局部線程數量
  28. qDebug()<<"pool:"<<pool.maxThreadCount()<<pool.expiryTimeout()<<"\r\nglobal"<<global_pool->maxThreadCount();
  29. qDebug()<<pool.activeThreadCount()<<global_pool->activeThreadCount();
  30. pool.start(run);
  31. global_pool->start(new MyRun);
  32. qDebug()<<pool.activeThreadCount()<<global_pool->activeThreadCount();
  33. pool.waitForDone();
  34. global_pool->waitForDone();
  35. qDebug()<<pool.activeThreadCount()<<global_pool->activeThreadCount();
  36. return 0;
  37. }

結果

  1. Main: 0x30c4
  2. pool: 2 30000
  3. global 4
  4. 0 0
  5. 1 1
  6. thread start: 0x22d0
  7. thread start: 0xfe0
  8. thread start: 0x22d0
  9. thread start: 0xfe0
  10. thread start: 0x22d0
  11. thread start: 0xfe0
  12. 0 0

當建立局部線程池,修改其參數后僅供局部使用,不會影響全局線程池的。

轉載請以鏈接形式標明本文標題和地址: Techie亮博客 » Qt多線程-QThreadPool線程池與QRunnable


免責聲明!

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



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