作者:CppExplore 網(wǎng)址:http://www.shnenglu.com/CppExplore/
廢話不多說,詳細介紹使用線程的優(yōu)點好處請參考baidu、google。
一、線程使用場景。使用線程的方式大致有兩種:
(1)流水線方式。根據(jù)業(yè)務(wù)特點,將一個流程的處理分割成多個線程,形成流水線的處理方式。產(chǎn)生的結(jié)果:延長單一流程的處理時間,提高系統(tǒng)整體的吞吐能力。
(2)線程池方式。針對處理時間比較長且沒有內(nèi)蘊狀態(tài)的線程,使用線程池方式分流消息,加快對線程消息的處理,避免其成為系統(tǒng)瓶頸。
線程使用的關(guān)鍵是 線程消息隊列、線程鎖、智能指針 的 使用。其中以線程消息隊列最為重要。
二、線程消息隊列描述。所謂線程消息隊列,就是一個普通的循環(huán)隊列(其它數(shù)據(jù)結(jié)構(gòu)也未嘗不可,具體內(nèi)容請參考數(shù)據(jù)結(jié)構(gòu)課本)加上“多生產(chǎn)者-單(多)消費者的PV操作”(詳細內(nèi)容請參考操作系統(tǒng)課本)。流水線方式中的線程是單消費者,線程池方式中的線程是多消費者。
為了后文更好的描述問題,作如下說明:
(1)假定循環(huán)隊列CircleQueue中,存放的消息指針類型是MyMSG *,入隊操作EnQueue,出隊操作DeQueue,判斷隊滿IsQueueFull,判斷隊空IsQueueEmpty。
(2)生產(chǎn)者消費者:生產(chǎn)者線程生產(chǎn)消息(MyMSG *),放在一個空緩沖區(qū)(CircleQueue)中,供消費者線程消費,生產(chǎn)者生產(chǎn)消息(EnQueue),如果緩沖區(qū)滿(IsQueueFull),則被阻塞,消費者消費消息(DeQueue),如果緩沖區(qū)空(IsQueueEmpty),則被阻塞。線程消息隊列就是生產(chǎn)者消費者問題中的緩沖區(qū),而它的生產(chǎn)者是不限定的,任何線程都可以作為生產(chǎn)者向其中進行EnQueue操作,消費線程則可能是一個,也可能是多個。因此對循環(huán)隊列的任何操作都要加鎖,以保證線程安全。
PV操作和鎖機制的基礎(chǔ)都是信號量。下面列出posix標準中給出的有關(guān)信號量的操作:







各個函數(shù)的詳細用法,請在linux/unix上查看man。
三、線程消息隊列實現(xiàn)。基于以上討論,下面給出線程消息隊列的實現(xiàn)(僅為了說明問題,非標準可運行代碼)。






























































四、線程消息隊列使用說明。將線程和線程消息隊列封裝在一起,形成帶有消息隊列的線程,其它線程向該線程的消息隊列插入消息,本線程取消息處理,之后再向其它線程的消息隊列插入消息,如此形成流水線運行方式。線程的創(chuàng)建可以使用posix的pthread_create函數(shù),或者boost的boost::thread。具體使用請查看相關(guān)文檔。另ACE中的ACE_Task實現(xiàn)了帶有消息隊列的線程,可以直接使用。
五、線程鎖描述。線程鎖,應(yīng)該都很熟悉,通常的實現(xiàn)以mutex面目示人。假設(shè)實現(xiàn)后的操作有:加鎖lock,解鎖unlock。
所謂線程鎖就是同一時間只能有一個線程擁有的鎖。當一個線程通過lock獲得線程鎖以后,在該線程持有該鎖的期間,其它進行獲取鎖操作的線程只能阻塞在lock操作處,但該線程可以繼續(xù)對鎖進行l(wèi)ock操作而不阻塞。
六、線程鎖實現(xiàn)

















































七、線程鎖使用說明。系統(tǒng)設(shè)計中應(yīng)該盡量減少鎖的使用。但有的時候無法避免,這時就是mutex登場的時候了。mutex的實現(xiàn),linux下有pthread_mutex_t,ACE里有ACE_Thread_Mutex,boost里有boost::mutex。為了高效的操作可以進一步實現(xiàn)出其它不同的鎖機制,比如常見的讀寫鎖,條件鎖,不再多說,有興趣可以自己去實現(xiàn),詳細可以參考操作系統(tǒng)課本。另linux/ACE/boost中均有實現(xiàn)。
lock和unlock要成對使用,但是很多情況下,一個函數(shù)有很多出口,再加上異常的情況,需要針對一個lock寫很多unlock,這樣不僅容易遺漏unlock,而且代碼也變得很丑陋。ACE中提供了Guard封裝mutex,使用起來比較方便,使用的時候不需要關(guān)心鎖的釋放,具體請看ACE。
也可以自己實現(xiàn)這種類Guard的功能。代碼如下:












使用的時候只需要在函數(shù)開始處寫std::auto_ptr<Guard> guard(new Guard(lock)) ;這屬于智能指針使用的一個小技巧。
八、使用智能指針的需求。在線程池方式中,為了去掉內(nèi)蘊狀態(tài),線程間不得不傳遞對象指針,這樣很難判斷指針的生命周期,難以找到釋放內(nèi)存空間的合適位置。智能指針完美解決了這個問題。boost中有boost::shared_ptr,ACE中有ACE_Refcounted_Auto_Ptr。本遍主要講述線程相關(guān),智能指針不再展開。
九、線程間消息傳遞框架。
(1)面向過程的消息傳遞。c語言常用方式。消息以結(jié)構(gòu)體的形式定義。














(2)面向?qū)ο蟮南鬟f。線程消息隊列中存儲command模式中ICommand類型的指針。消息發(fā)送線程實例化具體的command,消息處理線程取出command執(zhí)行command的execute方法。
缺點是:command比較多的時候,會生成大量的類文件,代碼不夠緊湊。
優(yōu)點則是可以方便的增加command而不需要過多改動已有代碼。