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