Qt中多執行緒的使用教程

2022-09-23 11:06:09 字數 4114 閱讀 7570

當執行緒的任務量比較大時,頻繁建立和銷毀執行緒會有很大的記憶體開銷,此時使用qthread的方法就不合適,應該使用執行緒池qthreadpool。qthread適用於常駐記憶體的任務,qthreadpool適用於不常駐記憶體,任務量比較大的情況。

qrunnable 是乙個非常輕量的抽象類,它的主體是純虛函式 qrunnable::run(),我們需要繼承它並實現這個函式。使用時需要將其子類的例項放進 qthreadpool 的執行佇列,執行緒池缺省會在執行後自動刪除這個例項。每乙個qt程式都有乙個全域性的執行緒池,我們可以直接使用它,這就不需要手動建立和管理執行緒池,呼叫qthreadpool::globalinstance()得到,可在多個類中共同使用乙個執行緒池。它預設最多建立 8 個執行緒,如果想改變最大執行緒數則呼叫 setmaxthreadcount() 進行修改,呼叫 activethreadcount() 檢視執行緒池中當前活躍的執行緒數。

qt並不是推薦使用其全域性執行緒池,何況實際的專案當中我們通常並不希望僅僅使用乙個全域性的執行緒池,而是在需要執行緒池的工程中都構建和維護自己乙個小小的執行緒池。用qthreadpool pool;的方式建立乙個區域性執行緒池,並由當前類維護,可保證此執行緒池僅供當前類應用。

定乙個任務類例如叫 task,繼承 qrunnable 並實現虛函式 run(),task 的物件作為 qthreadpool::start() 的引數就可以了,執行緒池會自動的**程中呼叫 task 的 run() 函式,非同步執行。執行緒池中的 qrunnable 物件太多時並不會立即為每乙個 qrunnable 物件建立乙個執行緒,而是讓它們排隊執行,同時最多有 maxthreadcount() 個執行緒並行執行。

void clear() //清除所有當前排隊但未開始執行的任務

int expirytimeout() const //執行緒長時間未使用將會自動退出節約資源,此函式返回等待時間

void setexpirytimeout(int expirytimeout) //設定執行緒**的等待時間

int maxthreadcount() const//執行緒池可維護的最大執行緒數量

setautodelete//用來標識是否在執行結束後自動由執行緒池釋放空間

bool waitfordone(int msecs=-1)//等待所有執行緒執行結束並退出,引數為等待時間-1表示一直等待到最後乙個執行緒退出**實現乙個qrunnable子類,構造函式引數是其id,run()裡輸出id和休眠1到3秒,析構函式裡輸出id:

class task : public qrunnable

;task::task(int id):

m_id(id)

{}void task::run()

task::~task()

main函式中的**:

qthreadpool pool;

pool.setmaxthreadcount(3);

for(int i=0;i<15;i++)

在main函式中建立乙個本地執行緒池,最大執行緒數為3,一次建立了15個執行緒,執行緒池不是乙個乙個執行執行緒,而是讓執行緒進入佇列,批量執行,每次3個。執行結果:

start thread 0 at 31:05.66

start thread 2 at 31:05.66

start thread 1 at 31:05.66

deconstruct task with id 2

deconstruct task with id 0

start thread 3 at 31:06.703

deconstruct task with id 1

start thread 4 at 31:06.704

start thread 5 at 31:06.704

deconstruct task with id 3

start thread 6 at 31:08.173

deconstruct task with id 5

start thread 7 at 31:08.173

deconstruct task with id 4

start thread 8 at 31:08.173

deconstruct task with id 6

start thread 9 at 31:09.507

deconstruct task with id 8

start thread 10 at 31:09.508

deconstruct task with id 7

start thread 11 at 31:09.508

deconstruct task with id 9

start thread 12 at 31:11.009

deconstruct task with id 10

start thread 13 at 31:11.009

deconstruct task with id 11

start thread 14 at 31:11.01

deconstruct task with id 14

deconstruct task with id 13

deconstruct task with id 12程式當中qrunnable是以指標的形式建立的,是qthreadpool在執行完執行緒後自動釋放,官方文件有一句:qthreadpool takes ownership and deletes qrunnable object automatically,這也是qt半自動記憶體**機制的一方面。

qrunnable 不是 qobject的子類,無法使用訊號與槽的機制與外界通訊的手段。實現與外界通訊有兩種方法:

1. 子類採用qobejct 和 qrunnable多重繼承,而且qobject要放在前面,再用訊號與槽的機制。

2. 使用`qmetaobject::invokemethod`。也就是說,執行緒通訊手段還是那兩種。

現在,用執行緒池實現前一篇的讀大檔案的程式,思路還是一樣的,修改task類的**如下:

class task : public qobject,public qrunnable

;void task::run()

主線程的部分程式:

// qthreadpool pool;

pool.setmaxthreadcount(1);

task *t = new task(1,this);

qthreadpool::globalinstance()->start(t);

// pool.start(t);

connect(t,signal(toline(qstring)),this,slot(appendtext(qstring)));修改上面的程式: 將emit toline(line)改為qmetaobject::invokemethod(m_w,"appendtext",qt::autoconnection,q_arg(qstring,line));

,主線程中將connect語句去掉即可。

上面的兩個程式必須用全域性執行緒池啟動執行緒,如果是本地執行緒池則無效,還是先執行次執行緒,阻塞主線程。

1.耗時的一次計算,i/o或者初始化:

不建議使用qthread,建議使用:qrunnable和qthreadpool結合使用或者直接用qtconcurrent::run

2.週期性的耗時計算或i/o:

使用繼承qobject和movetothread函式的方式,封裝到類中,然後後台執行緒啟動駐留,然後訊號槽傳送計算引數和接收計算的資料。

3.程式執行緒分模組,例如網路和資料庫單獨在乙個執行緒或者分別的執行緒設計:

使用繼承qobject和movetothread函式的方式,封裝到類中,然後後台執行緒啟動駐留,然後訊號槽傳送操作命令和取回結果。(注qwidget的ui操作只能在主線程的)。

4.多個任務執行者,分別的執行,乙個排程者:

每個封裝乙個類,然後執行者和排程者分執行緒,數個或者單個執行者乙個執行緒,通過訊號槽與排程者互動,用movetothread方式分執行緒。

5.程式中引用其他庫,其他庫且有獨立的事件迴圈:

用繼承qthread的方式,在run中啟用其他庫的事件迴圈,需要與主線程互動的部分採用自定義事件和qcoreapplication::postevent方式通訊。

6.當不得不重複呼叫乙個方法(比如每秒),許多人會引入多執行緒,在run中呼叫sleep(1),其實這是可以用qtimer的timeout訊號取代。

11 QT中多執行緒的使用

方法1 思路圖 直接上 主函式 include mainwindow.h include ui mainwindow.h include include mainwindow mainwindow qwidget parent qmainwindow parent ui new ui mainwin...

QT多執行緒的使用(moveToThread方法)

qt有兩種實現多執行緒的方法,一種是 子類化qthread,然後去重寫run函式,實現多執行緒 一種是 子類化qobject,然後使用movetothread函式實現多執行緒 由於qt官方推薦使用第二種方法,所以我這裡主要介紹一下,如何通過子類化qobject去實現多執行緒。首先,我們寫乙個繼承qo...

QT 多執行緒 使用UI

直接上 qt的ui操作必須在主線程做的,分支執行緒只能傳送訊息給主線程進行引導操作。所以平常我們的 都是直接使用乙個執行緒來調動ui,但是不同的執行緒同時需要使用ui來顯示結果之類的就需要相互協調 如果沒有invoke之類的方法,可以考慮直接使用qt 的qthread 直接使用thread會衝突 1...