Win32多线程编程(6) — 多线程协作及线程的池化管理
多線程級(jí)別的并行計(jì)算
寫多線程應(yīng)用程序最困難的地方在于如何使各線程的工作協(xié)調(diào)進(jìn)行。Windows提供的用于線程間通信的各種機(jī)制是很容易掌握的,可是要把它們應(yīng)用到工作中完成既定的功能時(shí)就會(huì)遇到這樣、那樣的困難。
對(duì)于常見的“生產(chǎn)者-消費(fèi)者”模型,只要采取合理同步措施實(shí)現(xiàn)數(shù)據(jù)交換的統(tǒng)一性即可。這類模型中的多線程往往任務(wù)獨(dú)立,主要兩類線程,一類寫線程(生產(chǎn)者),一類讀線程(消費(fèi)者)。但在實(shí)際應(yīng)用中,多核機(jī)器往往需要使用多線程來協(xié)作處理一項(xiàng)大規(guī)模的計(jì)算任務(wù),這涉及到并行計(jì)算的概念和多核編程技術(shù)。
如何讓多個(gè)處理器(多個(gè)線程)協(xié)作完成一項(xiàng)大規(guī)模的任務(wù),涉及到任務(wù)的分解和調(diào)度。因此,多核編程技術(shù)的關(guān)鍵問題在于如何將計(jì)算均勻分?jǐn)偟礁鱾€(gè)CPU核上。并行(Parallel)計(jì)算,即空間復(fù)用多個(gè)處理器,屬于線程級(jí)別上的協(xié)作。
關(guān)于多線程協(xié)作,參閱王艷平著《Windows程序設(shè)計(jì)》第3章《Win32程序的執(zhí)行單元》中的CRapidFinder例程。該例程演示了如何使用多線程協(xié)助完成文件搜索任務(wù)。
?
多進(jìn)程協(xié)助完成任務(wù)—分布式計(jì)算的濫觴
分布式計(jì)算則是進(jìn)程級(jí)別上的協(xié)作,它是一種把需要進(jìn)行大量計(jì)算的工程數(shù)據(jù)分割成小塊,由多臺(tái)計(jì)算機(jī)分別計(jì)算,在上傳運(yùn)算結(jié)果后再統(tǒng)一合并得出數(shù)據(jù)結(jié)論的技術(shù)。
現(xiàn)代大規(guī)模CG視覺特效的渲染系統(tǒng)有很多渲染節(jié)點(diǎn)組成,采用領(lǐng)先的分布式渲染技術(shù),系統(tǒng)將自動(dòng)確定網(wǎng)絡(luò)中可用的渲染節(jié)點(diǎn)和資源,同時(shí)將將任務(wù)分解到相應(yīng)渲染節(jié)點(diǎn),自動(dòng)負(fù)載平衡功能可以優(yōu)化工作流程中每個(gè)渲染節(jié)點(diǎn)的使用效率。
從《后天》到《2012》,再到《阿凡達(dá)》,這些大電影,其數(shù)以PB計(jì)艱苦卓絕的渲染工作無不依賴于現(xiàn)代分布式集群工作站的協(xié)同作戰(zhàn)。
?
線程的池化管理
通常情況下,內(nèi)存的分配和釋放通常都是mallloc和free顯式進(jìn)行的。對(duì)同一塊內(nèi)存的多次釋放通常會(huì)導(dǎo)致頁(yè)面錯(cuò)誤,而一直不釋放又導(dǎo)致內(nèi)存泄露,并且使系統(tǒng)性能大大下降。
頻繁地創(chuàng)建和銷毀內(nèi)存資源是很耗時(shí)間的,因?yàn)閯?chuàng)建一個(gè)對(duì)象要獲取內(nèi)存資源或者其它更多資源。malloc/free操縱的是進(jìn)程堆內(nèi)存,C/C++運(yùn)行庫(kù)不允許兩個(gè)線程同時(shí)從內(nèi)存堆中分配內(nèi)存,這種多線程同步操作也是相當(dāng)耗時(shí)的。
對(duì)于共享資源,有一個(gè)很著名的設(shè)計(jì)模式:資源池(Resource? Pool)。該模式正是為了解決資源的頻繁分配和釋放所造成的問題。如何利用已有對(duì)象來服務(wù)就是一個(gè)需要解決的關(guān)鍵問題,其實(shí)這就是一些“池化資源”技術(shù)產(chǎn)生的原因。數(shù)據(jù)庫(kù)連接池、內(nèi)存池等正是基于這一思想而產(chǎn)生的。
對(duì)于單核PC,多線程微觀串行;對(duì)于多處理器系統(tǒng),使用多線程技術(shù)可以充分發(fā)揮硬件的優(yōu)勢(shì)。理論上,安裝了N核CPU的PC,在某一時(shí)刻,系統(tǒng)底層所能并發(fā)執(zhí)行的線程個(gè)數(shù)為N。然而,線程的數(shù)量并不是多多益善。首先,線程這種內(nèi)核資源的創(chuàng)建和銷毀本身就很耗系統(tǒng)資源;其次,頻繁的線程上下文切換也會(huì)耗費(fèi)較多的CPU時(shí)鐘周期。借鑒數(shù)據(jù)庫(kù)連接池和內(nèi)存池的池化管理思想,對(duì)于線程也可以實(shí)行池化管理。
在討論WinSock的五種I/O模型中,選擇模型(select、WSAAsyncSelcet、WSAEventSelect)基于消息輪詢或事件等待,對(duì)于多用戶并發(fā)響應(yīng)往往為每個(gè)客戶連接創(chuàng)建一個(gè)I/O伺服線程。這種單連接單線程的處理方式,對(duì)于中小型服務(wù)器較為通用,但對(duì)大規(guī)模多用戶的服務(wù)器的高并發(fā)需求無能為力。完成端口模型本質(zhì)上利用了Win32重疊I/O機(jī)制,底層利用完成端口隊(duì)列對(duì)象來管理一個(gè)線程池。關(guān)于線程池規(guī)模,根據(jù)經(jīng)驗(yàn)為每個(gè)處理器創(chuàng)建2個(gè)線程,即工作線程數(shù)為CPU數(shù)的兩倍,因?yàn)椴⒉皇敲總€(gè)線程都是可調(diào)度的。參考《深度探索I/O完成端口》、《WinSock完成端口I/O模型》。
一個(gè)大規(guī)模高并發(fā)的服務(wù)器對(duì)于資源的管理至關(guān)重要,因此往往同時(shí)使用數(shù)據(jù)庫(kù)連接池、內(nèi)存池和線程池,對(duì)關(guān)鍵資源實(shí)行池化管理。
一般一個(gè)簡(jiǎn)單線程池至少包含下列組成部分。
線程池管理器(ThreadPoolManager):用于創(chuàng)建并管理線程池
工作線程(WorkThread):線程池中線程
任務(wù)接口(Task):每個(gè)任務(wù)必須實(shí)現(xiàn)的接口,以供工作線程調(diào)度任務(wù)的執(zhí)行。
任務(wù)隊(duì)列:用于存放沒有處理的任務(wù)。提供一種緩沖機(jī)制。
基于IOCP使用資源池化技術(shù)實(shí)現(xiàn)高性能的服務(wù)器,參閱王艷平、張?jiān)街禬indows網(wǎng)絡(luò)與通信程序設(shè)計(jì)》第4章《IOCP與可伸縮網(wǎng)絡(luò)程序》中的CIOCPServer例程。下圖為CIOCPServer的系統(tǒng)結(jié)構(gòu)圖。
CIOCPServer系統(tǒng)結(jié)構(gòu)圖
?
參考:
《線程池的介紹及簡(jiǎn)單實(shí)現(xiàn)》
《深入研究線程池》
《一個(gè)C++多線程程序開發(fā)庫(kù)》
《一個(gè)boost底下的線程池》
?
擴(kuò)展閱讀:
《百萬個(gè)人電腦投入破解科學(xué)難題》
《顛覆虛擬世界?《2012》電影幕后探秘》
《走進(jìn)為《阿凡達(dá)》進(jìn)行渲染的數(shù)據(jù)中心》
《從虛擬攝像到異構(gòu)計(jì)算-IT成就魔幻《阿凡達(dá)》》
總結(jié)
以上是生活随笔為你收集整理的Win32多线程编程(6) — 多线程协作及线程的池化管理的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Win32多线程编程(5) — 线程局部
- 下一篇: P2P的原理和常见的实现方式