有些人會覺得多執行緒無非是,有多少任務就啟動多少執行緒,creadthread,執行完了自己結束就釋放資源了,其實不然。多執行緒是需要管理的,執行緒的啟動、執行、等待和結束都需要管理,執行緒間如何通訊,如何共享記憶體資料,如果保證執行緒間的同步,避免死鎖,都要考慮。
以前做專案時,用過 codeproject 上乙個執行緒管理的** work queue[1],很好用,也是不錯的學習資料,但對於多執行緒初學者也不是一眼就能看懂的,所以今天打算對這個**做個解讀筆記,可為其它學習者提供乙個參考,也深化自己對多執行緒的理解。關於該類的使用可直接訪問原**。
這個多執行緒管理類為 cworkqueue,使用的是生產者-消費者模式。cworkqueue 建立的每個執行緒都是乙個消費者,生產者是類成員 m_pworkitemqueue。生產者資源由外界使用者通過 insertworkitem 成員函式注入,然後通過 releasesemaphore 通知消費者(即執行緒)處理,消費者執行緒 threadfunc 自建立起始就一直在等待,等待生產者通知,接到有任務通知後,執行緒就執行任務,執行完畢後繼續等待。
主線程通過兩種機制來跟已建立的新執行緒通訊,訊號量 semaphore 和 事件 event,semaphore 用於通知新執行緒執行任務,event 用於通知新執行緒結果自己。
1、訊號量 semaphore
由上可知,生產者和消費者使用的通訊機制是訊號量 semaphore。訊號量 semaphore 只有兩種狀態,觸發和未觸發,決定狀態的是當前資源數量,數量大於0表示訊號量處於觸發,等於0表示資源已經耗盡故訊號量處於末觸發。影響當前資源數量的函式有幾個,下面依次介紹。
首先 cworkqueue 在 create 函式中建立了 semaphore 訊號量,並存在成員變數 m_phsincobjectsarray[semaphore_index] 中,訊號量的初始計數為 0,最大計數為 2147483647l。
m_phsincobjectsarray[semaphore_index] = createsemaphore(null,0,long_max,null); //建立semaphore物件
每當使用者呼叫 insertworkitem 將工作任務插入到佇列(m_pworkitemqueue->push(pworkitem);)後,都要呼叫 releasesemaphore,這會增加訊號量的當前資源計數,該程式裡試加 1。
if (!releasesemaphore(m_phsincobjectsarray[semaphore_index],1,null))
在 cworkqueue 在 create 函式中還同時建立了執行緒,這些執行緒 threadfunc 自執行時就處於 waitformultipleobjects 狀態。等待函式會檢查訊號量的當前資源計數,如果大於0(即訊號量處於觸發狀態),減1後返回讓呼叫執行緒繼續執行。乙個執行緒可以多次呼叫等待函式來減小訊號量。執行緒中設定了無限迴圈 for(;;),因此當執行緒執行完當前處理後會繼續等待訊號量。
//等待兩個事件
dwwaitresult = waitformultipleobjects(number_of_sync_obj,pworkqueue->m_phsincobjectsarray,false,infinite);
2、事件 event
在 create 函式中建立訊號量 semaphore 的同時,還建立了事件, 並存在成員變數中,主要用於通知各執行緒結束執行。
m_phsincobjectsarray[abort_event_index] = createevent(null,true,false,null); //建立event 事件物件,初始化時為無訊號狀態,使用手動重置為無訊號狀態
當使用者呼叫 destroy 函式,會呼叫 setevent 觸發事件,然後 waitformultipleobjects 等待所有執行緒結束(注意到第三個引數為 true)。然後執行緒函式 threadfunc 探測到這個事件,會從 waitformultipleobjects(注意到第三個引數為 false) 返回,執行下面 abort_event_index 處理,結束執行緒。當所有的執行緒結束,接著 destroy 的 waitformultipleobjects 返回,做些清理的工作即結束執行緒管理。
因為訊號量和事件都是 handle,所以該類中把這兩個存在乙個陣列 m_phsincobjectsarray,通過列舉型變數來標識。
3、生產者 m_pworkitemqueue
使用者通過 insertworkitem 插入工作任務到佇列。
bool cworkqueue::insertworkitem(workitembase* pworkitem)
工作任務由要執行緒執行的函式,和 abort 函式,abort 函式用於最後呼叫 destroy 突然終止執行緒時,執行剩餘執行緒的清理工作。
classworkitembase
;
workitembase 需要使用者來繼承,並實現兩個虛函式。
class specificworkitem : publicworkitembase
;void specificworkitem::dowork(void*pthreadcontext)
void
specificworkitem::abort()
這樣在使用者執行 insertworkitem 插入任務到佇列後,通過 releasesemaphore 激發訊號量 semaphore,執行緒 threadfunc 會在 waitformultipleobjects 中探測到 semaphore 的激發狀態,然後獲得佇列中的任務,並刪除佇列中該任務防止其它執行緒重複執行,然後執行使用者的任務 pworkitem->dowork(pthreaddata),此處 pthreaddata 我沒用到,為 null 。
4、消費者 threadfunc
dword dwthreadid;pthread_context pthreadscontext ;
//建立所有的執行緒
for(i = 0 ; i < nnumberofthreads ; i++)
5、由消費者執行緒去訪問生產者資源可以看出,同乙個程序的執行緒可共享記憶體。使用者可以通過 specificworkitem 建構函式把資料和函式傳進成員變數和成員函式,通過 insertworkitem 把 specificworkitem 傳進 cworkqueue 的 m_pworkitemqueue,即生產者任務佇列,然後消費者執行緒會獲得通知,並訪問生產者提取任務,執行函式和資料。
管理類命令
管理類命令 hostname 顯示主機名稱 uname顯示系統資訊 top 顯示當前系統中耗費資源最多的程序 ps 顯示瞬間的程序狀態 du 顯示指定的檔案 目錄 已使用的磁碟空間的總量 df 顯示檔案系統磁碟空間的使用情況 free 顯示當前記憶體和交換空間的使用情況 ifconfig 顯示網路介...
管理類聯考
管理類聯考 數學 問題求解15題 條件充分性判斷10題,每題3分 共75分 高中 初中 小學數學知識的運用 邏輯推理 30題,每題2分 共60分 形式推理 論證推理 綜合推理 寫作論證有效性分析1題30分 論說文1題35分 共65分 論證有效性分析 較快地找出一段論證中的漏洞 論說文良好的議 寫作能...
理解Qt多執行緒類
point 1 qthread類的例項與普通類的例項沒什麼不同,只是執行著的run 函式會不同 例1 在mdialog中,使用 在mdialog中使用 1.connect this,signal sigdialogsignal mythread,slot slotthreadslot 當emit s...