多核時代:並行程序設計探討(3)——Windows和Linux對決(多進程多線程)
並行程序設計探討(3)——Windows和Linux對決(多進程多線程)
前麵的博文經過分析總結,最後得出兩種並行技術:多進程多線程、多機協作。對於多進程和多線程來說,最有代表性且最常見的的莫過於Windows和Linux(作為UNIX類操作係統的代表,下同)這兩個操作係統了。
真是冤家路窄,Windows和Linux這對冤家在這裏又碰麵了!!
當然,我這裏不是要挑起Windows和Linux誰優誰劣的爭論,對於一個真正的技術人來說,Windows和Linux本身並沒有優劣之分,隻有在不同的使用場景下用誰會更好的問題。之所以將Windows和Linux拿來對比,是因為對比更加容易讓人理解,記憶也更加深刻!
下麵我們首先從多進程和多線程的實現機製方麵來對比Windows和Linux。
多進程多線程實現機製
說起進程和線程,估計大家都會立刻想起那句耳熟能詳的解釋“進程是資源分配的最小單位,線程是運行的最小單位”!。
理論上來說這是對的,但實際上來說就不一定了,例如Windows有進程和線程的概念,而傳統UNIX卻隻有進程的概念(例如經典的《UNIX環境高級編程》中就沒有多線程的概念,但Solaris、AIX等又有另外的實現,此處暫且不表),Linux也有進程和線程的概念,但實現機製和Windows又不一樣,真是林子大了什麼鳥都有:)
有幾個進程、線程相關的概念首先要簡單介紹一下:
1.1 概念介紹
1.1.1 進程
資源分配最小單位,有的操作係統還是運行最小單位;
1.1.2 線程
運行最小單位,也是CPU調度的最小單位;
1.1.3 ULT、KLT
用戶態線程和內核態線程;主要的區分就是“誰來管理”線程,用戶態是用戶管理,內核態是內核管理(但肯定要提供一些API,例如創建)。
簡單對比兩者優劣勢:
1)可移植性:因為ULT完全在用戶態實現線程,因此也就和具體的內核沒有什麼關係,可移植性方麵ULT略勝一籌;
2)可擴展性:ULT是由用戶控製的,因此擴展也就容易;相反,KLT擴展就很不容易,基本上隻能受製於具體的操作係統內核;
3)性能:由於ULT的線程是在用戶態,對應的內核部分還是一個進程,因此ULT就沒有辦法利用多處理器的優勢,而KLT就可以通過調度將線程分布在多個處理上運行,這樣KLT的性能高得多;另外,一個ULT的線程阻塞,所有的線程都阻塞,而KLT一個線程阻塞不會影響其它線程。
4)編程複雜度:ULT的所有管理工作都要由用戶來完成,而KLT僅僅需要調用API接口,因此ULT要比KLT複雜的多;
1.1.4 POSIX
為了解決不同操作係統之間移植時接口不兼容而製定的接口標準,詳見維基百科解釋:https://zh.wikipedia.org/wiki/POSIX。
1.1.5 NPTL
為了解決Linux原有線程實現機製的缺陷而創立的一個開源項目,從2.4開始就有發布版本采用NPTL來實現多線程支持了。詳見維基百科解釋https://zh.wikipedia.org/wiki/Native_POSIX_Thread_Library。
1.1.6 LWP
Lightweight Process,輕量級進程,看名字有點奇怪,為什麼叫輕量級進程呢?為什麼又要用輕量級線程呢?
看了前麵ULT和KLT的比較,估計大家也發現了一個問題:所謂的ULT,因為不能利用多處理器的優勢和線程互相阻塞,其實完全不能堪重任,但對於傳統UNIX和Linux這類操作係統,內核設計和實現的時候就沒有線程這種對象,那怎麼實現多線程呢?
天才們於是想出了LWP這個招數,說白了這就是一個“山寨版的進程”,完全具有了山寨的一切特征:
文件係統是原來的進程的;
文件描述符是原來的進程的;
信號處理是原來的進程的;
地址空間是原來的進程的;
但就是進程ID不是原來的進程的,你說像不像BlackBerry的山寨版BlockBerry?
詳情請參考維基百科解釋:https://en.wikipedia.org/wiki/Light-weight_process
1.2 詳細對比
1.2.1 Windows
在此要向Windows致敬:至少相比Linux來說,Windows在線程上的支持是Linux不能比的(不要跟我提DOS哈)!
Windows的實現機製簡單來說就是前麵提到的KLT,即Windows在內核級別支持線程。每個Windows進程至少有一個線程,係統調度的時候也是調度線程。
當創建一個進程時,係統會自動創建它的第一個線程,稱為主線程。然後,該線程可以創建其他的線程,而這些線程又能創建更多的線程。
Windows已經提供了線程編程係列的API,這裏就不詳述了。
1.2.2 Linux
Linux不同的版本有不同的實現,2.0~2.4實現的是俗稱LinuxThreads的多線程方式,到了2.6,基本上都是NPTL的方式了。下麵我們分別介紹。
1.2.2.1 LinuxThreads
注:以下內容主要參考“楊沙洲 (mailto:pubb@163.net?subject=Linux 線程實現機製分析&cc=pubb@163.net)國防科技大學計算機學院”的“Linux 線程實現機製分析”。
這種實現本質上是一種LWP的實現方式,即通過輕量級進程來模擬線程,內核並不知道有線程這個概念,在內核看來,都是進程。
Linux采用的“一對一”的線程模型,即一個LWP對應一個線程。這個模型最大的好處是線程調度由內核完成了,而其他線程操作(同步、取消)等都是核外的線程庫函數完成的。
在LinuxThreads中,專門為每一個進程構造了一個管理線程,負責處理線程相關的管理工作。當進程第一次調用pthread_create()創建一個線程的時候就會創建並啟動管理線程。然後管理線程再來創建用戶請求的線程。也就是說,用戶在調用pthread_create後,先是創建了管理線程,再由管理線程創建了用戶的線程。
這種通過LWP的方式來模擬線程的實現看起來還是比較巧妙的,但也存在一些比較嚴重的問題:
1)線程ID和進程ID的問題
按照POSIX的定義,同一進程的所有的線程應該共享同一個進程和父進程ID,而Linux的這種LWP方式顯然不能滿足這一點。
2)信號處理問題
異步信號是以進程為單位分發的,而Linux的線程本質上每個都是一個進程,且沒有進程組的概念,所以某些缺省信號難以做到對所有線程有效,例如SIGSTOP和SIGCONT,就無法將整個進程掛起,而隻能將某個線程掛起。
3)線程總數問題
LinuxThreads將每個進程的線程最大數目定義為1024,但實際上這個數值還受到整個係統的總進程數限製,這又是由於線程其實是核心進程。
4)管理線程問題
管理線程容易成為瓶頸,這是這種結構的通病;同時,管理線程又負責用戶線程的清理工作,因此,盡管管理線程已經屏蔽了大部分的信號,但一旦管理線程死亡,用戶線程就不得不手工清理了,而且用戶線程並不知道管理線程的狀態,之後的線程創建等請求將無人處理。
5)同步問題
LinuxThreads中的線程同步很大程度上是建立在信號基礎上的,這種通過內核複雜的信號處理機製的同步方式,效率一直是個問題。
6)其他POSIX兼容性問題
Linux中很多係統調用,按照語義都是與進程相關的,比如nice、setuid、setrlimit等,在目前的LinuxThreads中,這些調用都僅僅影響調用者線程。
7)實時性問題
線程的引入有一定的實時性考慮,但LinuxThreads暫時不支持,比如調度選項,目前還沒有實現。不僅LinuxThreads如此,標準的Linux在實時性上考慮都很少。
1.2.2.2 NPTL的實現
NPTL,Native POSIX Thread Library,天生的POSIX線程庫。從命名上也可以看出所謂的NPTL就是針對原來的LinuxThreads的,不然為啥叫“Native”呢:)
本質上來說,NPTL還是一個LWP的實現機製,但相對原有LinuxThreads來說,做了很多的改進。下麵我們看一下NPTL如何解決原有LinuxThreads實現機製的缺陷。
1)線程ID和進程ID問題
新的exec函數能夠創建和原有進程ID一樣ID的新進程,這樣所有的線程ID都是一樣的;且/Proc目錄下隻會顯示進程的初始線程(初始線程就代表整個進程,類似於Windows的進程中第一個線程s),不會再像以前LinuxThreads機製時每個線程在proc目錄下都有記錄。
2)信號處理問題
內核實現了POSIX要求的線程信號處理機製,發送給進程的信號將由內核分發給一個合適的線程處理,對於致命和全局的信號(例如Stop,Continue, Pending),所有的線程都同步處理。
3)線程總數問題
內核經過擴展,能夠處理任意數量的線程。PID空間經過擴展後,在IA-32係統上能夠最大支持20億線程。
4)管理線程問題
去掉管理進程,管理進程的任務由擴展後的clone函數完成;增加了exit_group的係統調用,用於退出整個進程;
5)信號同步問題
實現了一個叫做Futex(Fase Userspace Mutex,注意不是Mutex)機製用來完成線程間同步,Futex的主要操作是在用戶態完成的,這樣解決了依靠內核信號機製進行同步的效率問題。詳細請參考https://zh.wikipedia.org/wiki/Futex。
當然,NPTL雖然做了很多改進,但依然不是100% POSIX兼容的,LinuxThreads的第6個和第7個問題在NPTL機製下依然沒有解決,但這並不掩蓋NPTL帶來的巨大改進,下麵是性能對比圖:
NPTL官方的文檔:https://people.redhat.com/drepper/nptl-design.pdf。
1.3 對決?
看了前麵的分析,大家可能納悶了,這哪裏是對決哦?全部是講Linux的實現了。
其實我也鬱悶,本來應該更加詳細的介紹Windows實現機製的,但由於Linux的不爭氣,全部用來變成對它的分析了。
==========================未完待續===============================
最後更新:2017-04-02 03:42:36
上一篇:
[原創]和Taskmgr過不去篇(無厘頭版)
下一篇:
Blowfish加密算法
java中文亂碼解決之道(五)—–java是如何編碼解碼的
智能快遞櫃工控主板選型要點分析
建設投入嚴重不足 構建全新網絡安全體係迫在眉睫
通過實例模擬ASP.NET MVC的Model綁定的機製:集合+字典
用TensorFlow和TensorBoard從零開始構建ConvNet(CNN)
胡曉明:保護客戶數據隱私是阿裏雲第一原則
自定義ContentProvider 實例演示
IBM ServerGuide引導安裝指南
tomcat中jsp引用圖片img的src屬性帶中文路徑無法顯示的解決
遊戲安全資訊精選 2017年第十一期 英國彩票網遭遇DDoS攻擊,中斷90分鍾 微軟“10月周二補丁日”發布63個漏洞補丁