針對Centos6.5系統,默認使用的是html
getconf GNU_LIBPTHREAD_VERSION NPTL 2.12
java
glic的版本是:glibc-2.12-1.166.el6_7.3.x86_64
linux
Non-Uniform Memory Access Architecture(NUMA) 參見:https://www.ibm.com/developerworks/cn/linux/l-numa/web
SMP(對稱多處理器)安全
當 Linux 最初開發時,在內核中並不能真正支持線程。可是它的確能夠經過 clone()
系統調用將進程做爲可調度的實體。這個調用建立了調用進程(calling process)的一個拷貝,這個拷貝與調用進程共享相同的地址空間。LinuxThreads 項目使用這個調用來徹底在用戶空間模擬對線程的支持。不幸的是,這種方法有一些缺點,尤爲是在信號處理、調度和進程間同步原語方面都存在問題。另外,這個線程模型也不符合 POSIX 的要求。網絡
要改進 LinuxThreads,很是明顯咱們須要內核的支持,而且須要重寫線程庫。有兩個相互競爭的項目開始來知足這些要求。一個包括 IBM 的開發人員的團隊開展了 NGPT(Next-Generation POSIX Threads)項目。同時,Red Hat 的一些開發人員開展了 NPTL 項目。NGPT 在 2003 年中期被放棄了,把這個領域徹底留給了 NPTL。多線程
儘管從 LinuxThreads 到 NPTL 看起來彷佛是一個必然的過程,可是若是您正在爲一個歷史悠久的 Linux 發行版維護一些應用程序,而且計劃很快就要進行升級,那麼如何遷移到 NPTL 上就會變成整個移植過程當中重要的一個部分。另外,咱們可能會但願瞭解兩者之間的區別,這樣就能夠對本身的應用程序進行設計,使其可以更好地利用這兩種技術。異步
本文詳細介紹了這些線程模型分別是在哪些發行版上實現的。jsp
線程 將應用程序劃分紅一個或多個同時運行的任務。線程與傳統的多任務進程 之間的區別在於:線程共享的是單個進程的狀態信息,並會直接共享內存和其餘資源。同一個進程中線程之間的上下文切換一般要比進程之間的上下文切換速度更快。所以,多線程程序的優勢就是它能夠比多進程應用程序的執行速度更快。另外,使用線程咱們能夠實現並行處理。這些相對於基於進程的方法所具備的優勢推進了 LinuxThreads 的實現。性能
LinuxThreads 最初的設計相信相關進程之間的上下文切換速度很快,所以每一個內核線程足以處理不少相關的用戶級線程。這就致使了一對一 線程模型的革命。
讓咱們來回顧一下 LinuxThreads 設計細節的一些基本理念:
LinuxThreads 很是出名的一個特性就是管理線程(manager thread)。管理線程能夠知足如下要求:
pthread_exit()
,那麼這個線程就沒法結束。主線程要進入睡眠狀態,而管理線程的工做就是在全部線程都被殺死以後來喚醒這個主線程。LinuxThreads 的設計一般均可以很好地工做;可是在壓力很大的應用程序中,它的性能、可伸縮性和可用性都會存在問題。下面讓咱們來看一下 LinuxThreads 設計的一些侷限性:
kill()
所發送的信號被傳遞到一些單獨的線程,而不是集中總體進行處理。這意味着若是有線程阻塞了這個信號,那麼 LinuxThreads 就只能對這個線程進行排隊,並在線程開放這個信號時在執行處理,而不是像其餘沒有阻塞信號的線程中同樣當即處理這個信號。setuid()
/setgid()
進程對於不一樣的線程來講可能都是不一樣的。NPTL,或稱爲 Native POSIX Thread Library,是 Linux 線程的一個新實現,它克服了 LinuxThreads 的缺點,同時也符合 POSIX 的需求。與 LinuxThreads 相比,它在性能和穩定性方面都提供了重大的改進。與 LinuxThreads 同樣,NPTL 也實現了一對一的模型。
Ulrich Drepper 和 Ingo Molnar 是 Red Hat 參與 NPTL 設計的兩名員工。他們的整體設計目標以下:
LD_ASSUME_KERNEL
,這會在本文稍後進行討論。與 LinuxThreads 相比,NPTL 具備不少優勢:
PTHREAD_PROCESS_SHARED
宏,使得開發人員可讓用戶級進程在不一樣進程的線程之間共享互斥鎖。getpid()
會爲全部的線程返回相同的進程 ID。例如,若是發送了 SIGSTOP
信號,那麼整個進程都會中止;使用 LinuxThreads,只有接收到這個信號的線程纔會中止。這樣能夠在基於 NPTL 的應用程序上更好地利用調試器,例如 GDB。LD_ASSUME_KERNEL
實現的,下面就來介紹這個特性。正如上面介紹的同樣,ABI 的引入使得能夠同時支持 NPTL 和 LinuxThreads 模型。基本上來講,這是經過 ld (一個動態連接器/加載器)來進行處理的,它會決定動態連接到哪一個運行時線程庫上。
舉例來講,下面是 WebSphere® Application Server 對這個變量所使用的一些通用設置;您能夠根據本身的須要進行適當的設置:
LD_ASSUME_KERNEL=2.4.19
:這會覆蓋 NPTL 的實現。這種實現一般都表示使用標準的 LinuxThreads 模型,並啓用浮動堆棧的特性。LD_ASSUME_KERNEL=2.2.5
:這會覆蓋 NPTL 的實現。這種實現一般都表示使用 LinuxThreads 模型,同時使用固定堆棧大小。咱們可使用下面的命令來設置這個變量:
export LD_ASSUME_KERNEL=2.4.19
注意,對於任何 LD_ASSUME_KERNEL
設置的支持都取決於目前所支持的線程庫的 ABI 版本。例如,若是線程庫並不支持 2.2.5 版本的 ABI,那麼用戶就不能將 LD_ASSUME_KERNEL
設置爲 2.2.5。一般,NPTL 須要 2.4.20,而 LinuxThreads 則須要 2.4.1。
若是您正運行的是一個啓用了 NPTL 的 Linux 發行版,可是應用程序倒是基於 LinuxThreads 模型來設計的,那麼全部這些設置一般均可以使用。
大部分現代 Linux 發行版都預裝了 LinuxThreads 和 NPTL,所以它們提供了一種機制來在兩者之間進行切換。要查看您的系統上正在使用的是哪一個線程庫,請運行下面的命令:
$ getconf GNU_LIBPTHREAD_VERSION
這會產生相似於下面的輸出結果:
NPTL 0.34
或者:
linuxthreads-0.10
表 1 列出了一些流行的 Linux 發行版,以及它們所採用的線程實現的類型、glibc 庫和內核版本。
表 1. Linux 發行版及其線程實現
線程實現 | C 庫 | 發行版 | 內核 |
---|---|---|---|
LinuxThreads 0.7, 0.71 (for libc5) | libc 5.x | Red Hat 4.2 | |
LinuxThreads 0.7, 0.71 (for glibc 2) | glibc 2.0.x | Red Hat 5.x | |
LinuxThreads 0.8 | glibc 2.1.1 | Red Hat 6.0 | |
LinuxThreads 0.8 | glibc 2.1.2 | Red Hat 6.1 and 6.2 | |
LinuxThreads 0.9 | Red Hat 7.2 | 2.4.7 | |
LinuxThreads 0.9 | glibc 2.2.4 | Red Hat 2.1 AS | 2.4.9 |
LinuxThreads 0.10 | glibc 2.2.93 | Red Hat 8.0 | 2.4.18 |
NPTL 0.6 | glibc 2.3 | Red Hat 9.0 | 2.4.20 |
NPTL 0.61 | glibc 2.3.2 | Red Hat 3.0 EL | 2.4.21 |
NPTL 2.3.4 | glibc 2.3.4 | Red Hat 4.0 | 2.6.9 |
LinuxThreads 0.9 | glibc 2.2 | SUSE Linux Enterprise Server 7.1 | 2.4.18 |
LinuxThreads 0.9 | glibc 2.2.5 | SUSE Linux Enterprise Server 8 | 2.4.21 |
LinuxThreads 0.9 | glibc 2.2.5 | United Linux | 2.4.21 |
NPTL 2.3.5 | glibc 2.3.3 | SUSE Linux Enterprise Server 9 | 2.6.5 |
注意,從 2.6.x 版本的內核和 glibc 2.3.3 開始,NPTL 所採用的版本號命名約定發生了變化:這個庫如今是根據所使用的 glibc 的版本進行編號的。
Java™ 虛擬機(JVM)的支持可能會稍有不一樣。IBM 的 JVM 能夠支持表 1 中 glibc 版本高於 2.1 的大部分發行版。
LinuxThreads 的限制已經在 NPTL 以及 LinuxThreads 後期的一些版本中獲得了克服。例如,最新的 LinuxThreads 實現使用了線程註冊來定位線程本地數據;例如在 Intel® 處理器上,它就使用了 %fs
和 %gs
段寄存器來定位訪問線程本地數據所使用的虛擬地址。儘管這個結果展現了 LinuxThreads 所採納的一些修改的改進結果,可是它在更高負載和壓力測試中,依然存在不少問題,由於它過度地依賴於一個管理線程,使用它來進行信號處理等操做。
您應該記住,在使用 LinuxThreads 構建庫時,須要使用 -D_REENTRANT
編譯時標誌。這使得庫線程是安全的。
最後,也許是最重要的事情,請記住 LinuxThreads 項目的建立者已經再也不積極更新它了,他們認爲 NPTL 會取代 LinuxThreads。
LinuxThreads 的缺點並不意味着 NPTL 就沒有錯誤。做爲一個面向 SMP 的設計,NPTL 也有一些缺點。我曾經看到過在最近的 Red Hat 內核上出現過這樣的問題:一個簡單線程在單處理器的機器上運行良好,但在 SMP 機器上卻掛起了。我相信在 Linux 上還有更多工做要作才能使它具備更好的可伸縮性,從而知足高端應用程序的需求。