Qt多線程-QThreadPool線程池與QRunnable

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

1. 介紹

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

2. QThreadPool

相關幫助文檔:QThreadPool多線程

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

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

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使用操做系統默認的堆棧大小。post

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.ui

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

maxThreadCount? reserveThread? activeThreadCount

因爲reserveThread 後的線程不計入線程數量,所以可能出現activeThreadCount>maxThreadCount? 狀況idea

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

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
相關文章
相關標籤/搜索