多線程 模型

有關多線程實現的疑問, 暫時想通一部分, 以此爲記。  (網上很多資料ms矛盾, 這裏僅取最*可能*的)

LWP: 輕量級線程,建立在內核上並由內核支持的用戶線程。它由clone()系統調用創建,參數是CLONE_VM(即與父進程共享地址空間和系統資源)。每一個LWP均與內核線程關聯,由內核管理並像普通進程一樣調度。

根據管理線程(即調度者)是在用戶態和內核態分爲內核級線程和用戶級線程,前者更利於併發使用多處理器的資源,而後者則更多考慮的是上下文切換開銷。

內核級線程特點:因爲線程切換時需要頻繁的進出內核態,故效率低;另外需要佔用內核的資源,線程數量有限制。(Linux不支持,Win NT支持,saloris 支持)。NT將所有的線程統一放進隊列調度(不管是否是同一個進程的),用戶線程和調度線程位於同一地址區間,線程切換時無需改動頁表,大大降低了系統調用的開銷,所以效率還可以。

用戶級線程:因爲切換時無需進入內核態(參setjmp.h)故效率高; 缺點是一個線程受阻時,所有該進程所有線程均受阻;同時單個進程的所有線程共享一個CPU,不能利用多CPU的優勢)。
用戶級線程有兩種實現形式:
1.運行時系統:完全由線程庫函數實現。 線程運行庫(run-time)在用戶線程每次進程系統調用的時候獲取控制權,然後再決定是轉發系統調用還是進行用戶線程調度(需要改寫原有的系統調用的用戶庫,插入用來和線程運行庫交互的代碼。這些插入的代碼被稱爲外套-jacket或是封裝器-wrapper)。如果線程很少系統調用,運行庫很少有機會運行,只能等用戶線程主動退出。
2. LWP  Linux線程使用clone函數創建參數爲(CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND)表示共享內存、共享文件系統訪問計數、共享文件描述符表,以及共享信號處理方式。

 

背景知識:

針對線程模型的兩大意義(併發使用多處理器和減少上下文切換開銷),線程模型按照調度者在覈內還是在覈外分爲核心級線程和用戶級線程兩種。目前的商用系統通常將兩者結合起來使用,既提供核心線程以滿足smp系統的需要,也支持用線程庫的方式在用戶態實現另一套線程機制,此時一個核心線程同時成爲多個用戶態線程的調度者。“混合”通常意味着更高的效率,但同時也意味着更大的實現難度。出於“簡單”的設計思路,Linux從一開始就沒有實現混合模型,它在實現上採用了另一種思路--LWP。

 

線程機制的實現,可以在操作系統內核,也可以在覈外。後者要求核內實現進程(前者一般也要求核內支持進程)。內核級線程模型顯然要求內核支持線程,而用戶級線程模型則不一定基於後者實現(即用戶級線程不一定基於核外線程來實現--比如,linux的用戶級線程採用LWP實現,不是核外的線程)。當核內既支持進程也支持線程時,就可以實現線程-進程的“多對多”模型,即一個進程的某個線程由內核調度,而同時它也可以作爲用戶級線程池的調度者,選擇合適的用戶級線程在其空間中運行--這就是“混合”模型。大多數商業操作系統(如Digital Unix、Solaris、Irix)採用這種完全實現POSIX1003.1c標準的線程模型。

核外實現的線程可以分爲“一對一”、“多對一”兩種模型,前者用一個核心進程(或輕量進程-注:這裏的核心進程只是說內核知曉進程/線程的存在,並不是內核線程kthread)對應一個線程,將線程調度等同於進程調度,交給核心完成;而後者則完全在覈外實現多線程,調度也在用戶態完成。後者即單純的用戶級線程模型,這種核外的線程調度只需完成線程棧的切換,開銷非常小;但因爲信號(無論是同步的還是異步的)是以進程爲單位的,無法定位到線程,所以不能用於多處理器系統,也是因爲如此,純用戶級線程的實現,除用於算法研究目的以外,幾乎已經消失了。

Linux內核只支持LWP,限制了更高效的線程模型(內核級線程),但Linux着重優化了進程的調度開銷,一定程度上彌補了這一缺陷。目前Linux最流行的LinuxThreads即Pthread採用“一對一”,將調度交給OS核心,而在用戶級實現一個包括信號處理在內的線程管理機制。

 

LinuxThreads存在的問題:

1. 因爲基於LWP而非核外線程實現,故同一進程的所有線程的PID不同。 (2.6下的新版本同一進程內的線程返回的pid是一樣。代碼如下:)

get_pid()
if (flags & CLONE_PID)
return current->pid;

 

2. 同樣,因爲LWP對於內核來說就是一個進程,同時也沒有線程組的概念,無法向進程中所有線程發送信號。LinuxThreads只能將一個線程掛起,而無法掛起整個進程。

3. 線程的總數有限制。

4. 線程管理瓶頸。一旦管理線程死了,後續的用戶線程需要用戶手工清理;同時也不能處理後續的創建線程請求。

5. 同步問題。因爲線程間通信採用信號的方式,效率一直是個問題。

6. POSIX兼容問題。很多系統調用僅僅適用於單個線程,而非進程下的所有線程。

7. 實時性問題。不僅pthread,即時linux沒有做太多。

2.6內核下的NPTL,繼續適用1:1模型,同時不再適用管理線程,將線程的管理直接放在覈內,優化了性能,缺點是仍沒有100%POSIX兼容。

 

 affinity: 線程的資源親和性,主要是指CPU的親和性。

int pthread_attr_setscope(pthread_attr_t*attr,intscope);

POSIX.1-2001 specifies two possible values forscope: PTHREAD_SCOPE_SYSTEM 和PTHREAD_SCOPE_PROCESS。POSIX.1-2001 only requires that an implementation support one of these contention scopes, but permits both to be supported. Linux supportsPTHREAD_SCOPE_SYSTEM, but notPTHREAD_SCOPE_PROCESS.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章