內核線程、輕量級進程、用戶線程

線程與進程概念

在現代操做系統中,進程支持多線程。html

  • 進程是資源管理的最小單元;git

  • 線程是程序執行的最小單元。算法

即線程做爲調度和分配的基本單位,進程做爲資源分配的基本單位數據庫

一個進程的組成實體能夠分爲兩大部分:線程集和資源集。進程中的線程是動態的對象;表明了進程指令的執行。資源,包括地址空間、打開的文件、用戶信息等等,由進程內的線程共享。服務器

線程概念的產生

傳統單線程進程的缺點

  1. 現實中有不少須要併發處理的任務,如數據庫的服務器端、網絡服務器、大容量計算等。網絡

  2. 傳統的UNIX進程是單線程的,單線程意味着程序必須是順序執行,不能併發;既在一個時刻只能運行在一個處理器上,所以不能充分利用多處理器框架的計算機。多線程

  3. 若是採用多進程的方法,則有以下問題:併發

    • fork一個子進程的消耗是很大的,fork是一個昂貴的系統調用,即便使用現代的寫時複製(copy-on-write)技術。
    • 各個進程擁有本身獨立的地址空間,進程間的協做須要複雜的IPC技術,如消息傳遞和共享內存等。

多線程的優缺點

多線程的優勢和缺點其實是對立統一的。框架

支持多線程的程序(進程)能夠取得真正的並行(parallelism),且因爲共享進程的代碼和全局數據,故線程間的通訊是方便的。它的缺點也是因爲線程共享進程的地址空間,所以可能會致使競爭,所以對某一塊有多個線程要訪問的數據須要一些同步技術。異步

線程的設計過程演變

在操做系統設計上,從進程演化出線程,最主要的目的就是更好的支持SMP以及減少(進程/線程)上下文切換開銷。

SMP機器上多線程的並行性

不管按照怎樣的分法,一個進程至少須要一個線程做爲它的指令執行體,進程管理着資源(好比cpu、內存、文件等等),而將線程分配到某個cpu上執 行。

一個進程固然能夠擁有多個線程,此時,若是進程運行在SMP機器上,它就能夠同時使用多個cpu來執行各個線程,達到最大程度的並行,以提升效率;同 時,即便是在單cpu的機器上,採用多線程模型來設計程序,正如當年採用多進程模型代替單進程模型同樣,使設計更簡潔、功能更完備,程序的執行效率也更 高,例如採用多個線程響應多個輸入,而此時多線程模型所實現的功能實際上也能夠用多進程模型來實現,而與後者相比,線程的上下文切換開銷就比進程要小多 了,從語義上來講,同時響應多個輸入這樣的功能,實際上就是共享了除cpu之外的全部資源的。

線程模型–核心級線程和用戶級線程

針對線程模型的兩大意義,分別開發出了核心級線程用戶級線程兩種線程模型,分類的標準主要是線程的調度者在覈內仍是在覈外。前者更利於併發使用多處理器的資源,然後者則更多考慮的是上下文切換開銷。

關於線程的實現模型,能夠參見博主的另一篇博客線程的3種實現方式–內核級線程, 用戶級線程和混合型線程

目前的實現策略

在目前的商用系統中,一般都將二者結合起來使用,既提供核心線程以知足smp系統的須要,也支持用線 程庫的方式在用戶態實現另外一套線程機制,此時一個核心線程同時成爲多個用戶態線程的調度者。

正如不少技術同樣,」混合」一般都能帶來更高的效率,但同時也 帶來更大的實現難度,出於」簡單」的設計思路,Linux從一開始就沒有實現混合模型的計劃,但它在實現上採用了另外一種思路的」混合」。

在線程機制的具體實現上,能夠在操做系統內核上實現線程,也能夠在覈外實現,後者顯然要求核內至少實現了進程,而前者則通常要求在覈內同時也支持進 程。核心級線程模型顯然要求前者的支持,而用戶級線程模型則不必定基於後者實現。這種差別,正如前所述,是兩種分類方式的標準不一樣帶來的。

當核內既支持進程也支持線程時,就能夠實現線程-進程的」多對多」模型,即一個進程的某個線程由核內調度,而同時它也能夠做爲用戶級線程池的調度 者,選擇合適的用戶級線程在其空間中運行。這就是前面提到的」混合」線程模型,既可知足多處理機系統的須要,也能夠最大限度的減少調度開銷。

絕大多數商業 操做系統(如Digital Unix、Solaris、Irix)都採用的這種可以徹底實現POSIX1003.1c標準的線程模型。在覈外實現的線程又能夠分爲」一對一」、」多對 一」兩種模型,前者用一個核心進程(也許是輕量進程)對應一個線程,將線程調度等同於進程調度,交給核心完成,然後者則徹底在覈外實現多線程,調度也在用 戶態完成。後者就是前面提到的單純的用戶級線程模型的實現方式,顯然,這種核外的線程調度器實際上只須要完成線程運行棧的切換,調度開銷很是小,但同時因 爲核心信號(不管是同步的仍是異步的)都是以進程爲單位的,於是沒法定位到線程,因此這種實現方式不能用於多處理器系統,而這個需求正變得愈來愈大,因 此,在現實中,純用戶級線程的實現,除算法研究目的之外,幾乎已經消失了。

Linux內核只提供了輕量進程的支持,限制了更高效的線程模型的實現,但Linux着重優化了進程的調度開銷,必定程度上也彌補了這一缺陷。目前 最流行的線程機制LinuxThreads所採用的就是線程-進程」一對一」模型,調度交給核心,而在用戶級實現一個包括信號處理在內的線程管理機制。

三種線程概念——內核線程、輕量級進程、用戶線程

內核線程

內核線程就是內核的分身,一個分身能夠處理一件特定事情。這在處理異步事件如異步IO時特別有用。內核線程的使用是廉價的,惟一使用的資源就是內核棧和上下文切換時保存寄存器的空間。支持多線程的內核叫作多線程內核(Multi-Threads kernel )。

內核線程只運行在內核態,不受用戶態上下文的拖累。

  • 處理器競爭:能夠在全系統範圍內競爭處理器資源;

  • 使用資源:惟一使用的資源是內核棧和上下文切換時保持寄存器的空間

  • 調度:調度的開銷可能和進程自身差很少昂貴

  • 同步效率:資源的同步和數據共享比整個進程的數據同步和共享要低一些。

輕量級進程

輕量級進程(LWP)是創建在內核之上並由內核支持的用戶線程,它是內核線程的高度抽象,每個輕量級進程都與一個特定的內核線程關聯。內核線程只能由內核管理並像普通進程同樣被調度。

a LWP runs in user space on top of a single kernel thread and shares its address space and system resources with other LWPs within the same process

輕量級進程由clone()系統調用建立,參數是CLONE_VM,即與父進程是共享進程地址空間和系統資源。

與普通進程區別:LWP只有一個最小的執行上下文和調度程序所需的統計信息。

  • 處理器競爭:因與特定內核線程關聯,所以能夠在全系統範圍內競爭處理器資源

  • 使用資源:與父進程共享進程地址空間

  • 調度:像普通進程同樣調度

輕量級線程(LWP)是一種由內核支持的用戶線程。它是基於內核線程的高級抽象,所以只有先支持內核線程,纔能有LWP。每個進程有一個或多個LWPs,每一個LWP由一個內核線程支持。這種模型實際上就是恐龍書上所提到的一對一線程模型。在這種實現的操做系統中,LWP就是用戶線程。

因爲每一個LWP都與一個特定的內核線程關聯,所以每一個LWP都是一個獨立的線程調度單元。即便有一個LWP在系統調用中阻塞,也不會影響整個進程的執行。

輕量級進程具備侷限性。

  • 首先,大多數LWP的操做,如創建、析構以及同步,都須要進行系統調用。系統調用的代價相對較高:須要在user mode和kernel mode中切換。

  • 其次,每一個LWP都須要有一個內核線程支持,所以LWP要消耗內核資源(內核線程的棧空間)。所以一個系統不能支持大量的LWP。

這裏寫圖片描述

注:

  1. LWP的術語是借自於SVR4/MP和Solaris 2.x。
  2. 有些系統將LWP稱爲虛擬處理器。
  3. 將之稱爲輕量級進程的緣由多是:在內核線程的支持下,LWP是獨立的調度單元,就像普通的進程同樣。因此LWP的最大特色仍是每一個LWP都有一個內核線程支持。

用戶線程

用戶線程是徹底創建在用戶空間的線程庫,用戶線程的建立、調度、同步和銷燬全又庫函數在用戶空間完成,不須要內核的幫助。所以這種線程是極其低消耗和高效的。

  • 處理器競爭:單純的用戶線程是創建在用戶空間,其對內核是透明的,所以其所屬進程單獨參與處理器的競爭,而進程的全部線程參與競爭該進程的資源。

  • 使用資源:與所屬進程共享進程地址空間和系統資源。

  • 調度:由在用戶空間實現的線程庫,在所屬進程內進行調度

LWP雖然本質上屬於用戶線程,但LWP線程庫是創建在內核之上的,LWP的許多操做都要進行系統調用,所以效率不高。而這裏的用戶線程指的是徹底創建在用戶空間的線程庫,用戶線程的創建,同步,銷燬,調度徹底在用戶空間完成,不須要內核的幫助。所以這種線程的操做是極其快速的且低消耗的。

這裏寫圖片描述

上圖是最初的一個用戶線程模型,從中能夠看出,進程中包含線程,用戶線程在用戶空間中實現,內核並無直接對用戶線程進程調度,內核的調度對象和傳統進程同樣,仍是進程自己,內核並不知道用戶線程的存在。

用戶線程之間的調度由在用戶空間實現的線程庫實現。

這種模型對應着恐龍書中提到的多對一線程模型,其缺點是一個用戶線程若是阻塞在系統調用中,則整個進程都將會阻塞。

增強版的用戶線程——用戶線程+LWP

這種模型對應着恐龍書中多對多模型。

用戶線程庫仍是徹底創建在用戶空間中,所以用戶線程的操做仍是很廉價,所以能夠創建任意多須要的用戶線程。

操做系統提供了LWP做爲用戶線程和內核線程之間的橋樑。LWP仍是和前面提到的同樣,具備內核線程支持,是內核的調度單元,而且用戶線程的系統調用要經過LWP,所以進程中某個用戶線程的阻塞不會影響整個進程的執行。

用戶線程庫將創建的用戶線程關聯到LWP上,LWP與用戶線程的數量不必定一致。當內核調度到某個LWP上時,此時與該LWP關聯的用戶線程就被執行。

這裏寫圖片描述

Linux使用的線程庫

LinuxThreads是用戶空間的線程庫,所採用的是線程-進程1對1模型(即一個用戶線程對應一個輕量級進程,而一個輕量級進程對應一個特定的內核線程),將線程的調度等同於進程的調度,調度交由內核完成,而線程的建立、同步、銷燬由核外線程庫完成(LinuxThtreads已綁定到 GLIBC中發行)。

在LinuxThreads中,由專門的一個管理線程處理全部的線程管理工做。當進程第一次調用pthread_create()建立線程時就會先 建立(clone())並啓動管理線程。後續進程pthread_create()建立線程時,都是管理線程做爲pthread_create()的調用者的子線程,經過調用clone()來建立用戶線程,並記錄輕量級進程號和線程id的映射關係,所以,用戶線程實際上是管理線程的子線程。

LinuxThreads只支持調度範圍爲PTHREAD_SCOPE_SYSTEM的調度,默認的調度策略是SCHED_OTHER。 
用戶線程調度策略也可修改爲SCHED_FIFO或SCHED_RR方式,這兩種方式支持優先級爲0-99,而SCHED_OTHER只支持0。

  • SCHED_OTHER 分時調度策略,

  • SCHED_FIFO 實時調度策略,先到先服務

  • SCHED_RR 實時調度策略,時間片輪轉

SCHED_OTHER是普通進程的,後兩個是實時進程的(通常的進程都是普通進程,系統中出現實時進程的機會不多)。SCHED_FIFO、 SCHED_RR優先級高於全部SCHED_OTHER的進程,因此只要他們可以運行,在他們運行完以前,全部SCHED_OTHER的進程的都沒有獲得 執行的機會

 

 

 

參考:

關於進程、線程和輕量級進程的一些筆記

清華大學操做系統原理

[維基百科-輕量級進程]

相關文章
相關標籤/搜索