因爲歷史緣由,2.5.x之前的linux對pthreads沒有提供內核級的支持,因此在linux上的pthreads實現只能採用n:1的方式,也稱爲庫實現。html
線程的實現,經歷了以下發展階段:linux
目前,pthreads的實現有3種方式:算法
(1)第一種,多對一,linux Threads,也就是庫實現。shell
linux Threads,這是linux標準的的線程庫,可是與IEEE的POSIX不兼容. 在LinuxThreads中,專門爲每個進程構造了一個管理線程,負責處理線程相關的管理工做。當進程第一次調用pthread_create()建立一個線程的時候就會建立並啓動管理線程。而後管理線程再來建立用戶請求的線程。也就是說,用戶在調用pthread_create後,先是建立了管理線程,再由管理線程建立了用戶的線程。編程
(2)第二種,1:1模式。 NPTL多線程
1:1模式適合CPU密集型的機器。咱們知道,進程(線程)在運行中會因爲等待某種資源而阻塞,多是I/O資源,也多是CPU。在多CPU機器上1:1模式是個很不錯的選擇。所以1:1的優勢就是,可以充分發揮SMP的優點。
這種模式也有它的缺點。因爲OS爲每一個線程創建一個內核線程,致使內核級的內存空間(IA32機器的4G虛存空間的最高1G)的大開銷。第二個缺點在於,在傳統意義上,在mutex互斥鎖和條件變量上的操做要求進入內核態,這是由於OS負責調度,它要爲線程的轉態轉換負全責。後面咱們會看到,Linux的NPTL庫避免了這個缺點,它的互斥鎖與條件變量的操做在用戶態完成。post
(3)第三種,M:N模式。測試
這種模式試圖兼有上面2種模式的優勢。它要求一個分層的模型。比方說,某個進程內有4個線程,其中每2個線程對應一個內核線程。這樣,OS知道2個實體的存在,負責它們的調度。而在一個實體內有2個線程,這2個線程間的調度就是OS不加干涉、也不知道的了。
簡單的說,M:N模型的OS級調度上,跟1:1模型類似;線程間調度上,跟n:1模型類似。
優勢是,既能夠在進程內利用SMP的優點,又能夠節省系統空間內存的消耗,並且環境切換大多在用戶態完成。
缺點是顯然的:複雜。spa
Linux線程是經過進程來實現。Linux kernel爲進程建立提供一個clone()系統調用,clone的參數包括如 CLONE_VM, CLONE_FILES, CLONE_SIGHAND 等。經過clone()的參數,新建立的進程,也稱爲LWP(Lightweight process)與父進程共享內存空間,文件句柄,信號處理等,從而達到建立線程相同的目的。操作系統
普通進程和LWP在實現上的不一樣點是:
線程和LWP是同一個東西,只是在用戶態,咱們管進程中每個執行序列爲「線程」,可是內核中它被稱爲LWP。由於內核上沒有線程的概念,CPU的調度是以進程爲單位的。
在Linux 2.6以前,Linux kernel並無真正的thread支持,一些thread library都是在clone()基礎上的一些基於user space的封裝,所以一般在信號處理、進程調度(每一個進程須要一個額外的調度線程)及多線程之間同步共享資源等方面存在必定問題。Linux 2.6的線程庫叫NPTL(Native POSIX Thread Library)。POSIX thread(pthread)是一個編程規範,經過此規範開發的多線程程序具備良好的跨平臺特性。儘管是基於進程的實現,但新版的NPTL建立線程的效率很是高。一些測試顯示,基於NPTL的內核建立10萬個線程只須要2秒,而沒有NPTL支持的內核則須要長達15分鐘。
在Linux中,每個線程都有一個task_struct。線程和進程可使用同一調度其調度。內核角度上來將LWP和Process沒有區別,有的僅僅是資源的共享。若是獨享資源則是HWP,共享資源則是LWP。而在真正內核實現的NPTL的實現是在kernel增長了futex(fast userspace mutex)支持用於處理線程之間的sleep與wake。futex是一種高效的對共享資源互斥訪問的算法。kernel在裏面起仲裁做用,但一般都由進程自行完成。NPTL是一個1×1的線程模型,即一個線程對於一個操做系統的調度進程,優勢是很是簡單。而其餘一些操做系統好比Solaris則是MxN的,M對應建立的線程數,N對應操做系統能夠運行的實體。(N<M),優勢是線程切換快,但實現稍複雜。
注:
(1)pthread線程庫--NPTL(Native POSIX Threading Library)
在1:1核心線程模型中,應用程序建立的每個線程(也有書稱爲LWP)都由一個核心線程直接管理。OS內核將每個核心線程都調到系統CPU上,
所以,全部線程都工做在「系統競爭範圍」(system contention scope):線程直接和「系統範圍」內的其餘線程競爭。
(2)NGPT(Next Generation POSIX Threads)
N:M混合線程模型提供了兩級控制,將用戶線程映射爲系統的可調度體以實現並行,這個可調度體稱爲輕量級進程(LWP:light weight process),LWP
再一一映射到核心線程。以下圖所示。OS內核將每個核心線程都調到系統CPU上,所以,全部線程都工做在「系統競爭範圍」。
添加:各階段線程的具體實現
在LinuxThreads中,專門爲每個進程構造了一個管理線程,負責處理線程相關的管理工做。當進程第一次調用pthread_create()建立一個線程的時候就會建立並啓動管理線程。而後管理線程再來建立用戶請求的線程。也就是說,用戶在調用pthread_create後,先是建立了管理線程,再由管理線程建立了用戶的線程。
爲了遵循POSIX對線程的一個規定:當"進程"收到一個致命信號(好比因爲段錯誤收到SIGSEGV信號), 進程內的線程所有退出
,LinuxThreads的實現方法:
容易發現,管理線程可能成爲多線程系統的瓶頸,線程建立和銷燬的開銷很大(須要IPC)。
更爲重要的是,LinuxThreads沒法知足Posix對線程的絕大多數規定,好比:
在linux 2.6中, 內核有了線程組的概念, task_struct結構中增長了一個tgid(thread group id)字段.
若是這個task是一個"主線程", 則它的tgid等於pid, 不然tgid等於進程的pid(即主線程的pid).
經過以下方式,解決了LinuxThreads不能兼容POSIX的問題:
上面提到的兩種線程庫使用的都是內核級線程(每一個線程都對應內核中的一個調度實體), 這種模型稱爲1:1模型(1個線程對應1個內核級線程);
而NGPT則打算實現M:N模型(M個線程對應N個內核級線程), 也就是說若干個線程多是在同一個執行實體上實現的.
由於模型太複雜,貌似沒有實現出來全部預約功能,因此被放棄了。
參考連接
Linux進程、線程模型,LWP,pthread_self() http://blog.csdn.net/tianyue168/article/details/7403693