線程的3種實現方式--內核級線程, 用戶級線程和混合型線程


之前講解過內核線程、輕量級進程、用戶線程三種線程概念解惑(線程≠輕量級進程), 但是一直對其中提到的線程的實現模型比較迷惑, 這次就花了點時間怎么學習了一下子

1 線程的3種實現方式


在傳統的操作系統中,擁有資源和獨立調度的基本單位都是進程。在引入線程的操作系統中,線程是獨立調度的基本單位,進程是資源擁有的基本單位。在同一進程中,線程的切換不會引起進程切換。在不同進程中進行線程切換,如從一個進程內的線程切換到另一個進程中的線程時,會引起進程切換

根據操作系統內核是否對線程可感知,可以把線程分為內核線程和用戶線程

名稱 描述
用戶級線程(User-LevelThread, ULT)  由應用程序所支持的線程實現, 內核意識不到用戶級線程的實現
內核級線程(Kemel-LevelThread, KLT)  內核級線程又稱為內核支持的線程

 

在多線程操作系統中,各個系統的實現方式並不相同,在有的系統中實現了用戶級線程,有的系統中實現了內核級線程


有些情況下,也把內核級線程叫做輕量級進程(LWP), 但是這個是一個不准備的描述, 其實LWP的術語是借自於SVR4/MP和Solaris 2.x系統中, 有些系統將LWP稱為虛擬處理器, 將之稱為輕量級進程的原因可能是, 在內核線程的支持下,LWP是獨立的調度單元,就像普通的進程一樣。所以LWP的最大特點還是每個LWP都有一個內核線程支持

2 用戶級線程(多對一模型)


2.1 線程的用戶級線程實現方式
在用戶級線程中,

有關線程管理的所有工作都由應用程序完成,內核意識不到線程的存在. 應用程序可以通過使用線程庫設計成多線程程序. 通常,應用程序從單線程起始,在該線程中開始運行,在其運行的任何時刻,可以通過調用線程庫中的派生例程創建一個在相同進程中運行的新線程。

用戶級線程僅存在於用戶空間中,此類線程的創建、撤銷、線程之間的同步與通信功能,都無須利用系統調用來實現。用戶進程利用線程庫來控制用戶線程。由於線程在進程內切換的規則遠比進程調度和切換的規則簡單,不需要用戶態/核心態切換,所以切換速度快。由於這里的處理器時間片分配是以進程為基本單位,所以每個線程執行的時間相對減少為了在操作系統中加入線程支持,采用了在用戶空間增加運行庫來實現線程,這些運行庫被稱為“線程包”,用戶線程是不能被操作系統所感知的。用戶線程多見於一些歷史悠久的操作系統,例如Unix操作系統

用戶級線程駐留在用戶空間或模式。運行時庫管理這些線程,它也位於用戶空間。它們對於操作系統是不可見的,因此無法被調度到處理器內核。每個線程並不具有自身的線程上下文。因此,就線程的同時執行而言,任意給定時刻每個進程只能夠有一個線程在運行,而且只有一個處理器內核會被分配給該進程。對於一個進程,可能有成千上萬個用戶級線程,但是它們對系統資源沒有影響。運行時庫調度並分派這些線程。

下圖說明了用戶級線程的實現方式,

 

 

 

如同在圖中看到的那樣,庫調度器從進程的多個線程中選擇一個線程,然后該線程和該進程允許的一個內核線程關聯起來。內核線程將被操作系統調度器指派到處理器內核。用戶級線程是一種”多對一”的線程映射

2.2 用戶級線程的特點
內核對線程包一無所知。從內核角度考慮,就是按正常的方式管理,即單線程進程(存在運行時系統)

2.3 用戶級線程的優點
用戶線程的優點主要有

可以在不支持線程的操作系統中實現。

創建和銷毀線程、線程切換代價等線程管理的代價比內核線程少得多, 因為保存線程狀態的過程和調用程序都只是本地過程

允許每個進程定制自己的調度算法,線程管理比較靈活。這就是必須自己寫管理程序,與內核線程的區別

線程能夠利用的表空間和堆棧空間比內核級線程多

不需要陷阱,不需要上下文切換,也不需要對內存高速緩存進行刷新,使得線程調用非常快捷

線程的調度不需要內核直接參與,控制簡單。
2.4 用戶線程的缺點
用戶線程的缺點主要有

線程發生I/O或頁面故障引起的阻塞時,如果調用阻塞系統調用則內核由於不知道有多線程的存在,而會阻塞整個進程從而阻塞所有線程, 因此同一進程中只能同時有一個線程在運行

頁面失效也會產生類似的問題。

一個單獨的進程內部,沒有時鍾中斷,所以不可能用輪轉調度的方式調度線程

資源調度按照進程進行,多個處理機下,同一個進程中的線程只能在同一個處理機下分時復用

補充
在用戶級線程中,每個進程里的線程表由運行時系統管理。當一個線程轉換到就緒狀態或阻塞狀態時,在該線程表中存放重新啟動該線程所需的信息,與內核在進程表中存放的進程的信息完全一樣

3 內核級線程


3.1 線程的內核級線程實現
在內核級線程中,

內核線程建立和銷毀都是由操作系統負責、通過系統調用完成的。在內核的支持下運行,無論是用戶進程的線程,或者是系統進程的線程,他們的創建、撤銷、切換都是依靠內核實現的。

線程管理的所有工作由內核完成,應用程序沒有進行線程管理的代碼,只有一個到內核級線程的編程接口. 內核為進程及其內部的每個線程維護上下文信息,調度也是在內核基於線程架構的基礎上完成。圖2-2(b)說明了內核級線程的實現方式。


內核線程駐留在內核空間,它們是內核對象。有了內核線程,每個用戶線程被映射或綁定到一個內核線程。用戶線程在其生命期內都會綁定到該內核線程。一旦用戶線程終止,兩個線程都將離開系統。這被稱作”一對一”線程映射,

  1.線程的創建、撤銷和切換等,都需要內核直接實現,即內核了解每一個作為可調度實體的線程

  2.這些線程可以在全系統內進行資源的競爭

  3.內核空間內為每一個內核支持線程設置了一個線程控制塊(TCB),內核根據該控制塊,感知線程的存在,並進行控制

如圖所示,即內核級線程的實現方式, 每個用戶線程都直接與一個內核線程相關聯.

 


操作系統調度器管理、調度並分派這些線程。運行時庫為每個用戶級線程請求一個內核級線程。操作系統的內存管理和調度子系統必須要考慮到數量巨大的用戶級線程。您必須了解每個進程允許的線程的最大數目是多少。操作系統為每個線程創建上下文。進程的每個線程在資源可用時都可以被指派到處理器內核。

3.2 內核線程的特點
當某個線程希望創建一個新線程或撤銷一個已有線程時,它進行一個系統調用

3.3 內核線程的優點
內核線程的優點:

1.多處理器系統中,內核能夠並行執行同一進程內的多個線程

2.如果進程中的一個線程被阻塞,能夠切換同一進程內的其他線程繼續執行(用戶級線程的一個缺點)

3.所有能夠阻塞線程的調用都以系統調用的形式實現,代價可觀

4.當一個線程阻塞時,內核根據選擇可以運行另一個進程的線程,而用戶空間實現的線程中,運行時系統始終運行自己進程中的線程

5.信號是發給進程而不是線程的,當一個信號到達時,應該由哪一個線程處理它?線程可以“注冊”它們感興趣的信號

4 組合方式


在一些系統中,使用組合方式的多線程實現, 線程創建完全在用戶空間中完成,線程的調度和同步也在應用程序中進行. 一個應用程序中的多個用戶級線程被映射到一些(小於或等於用戶級線程的數目)內核級線程上。

下圖說明了用戶級與內核級的組合實現方式, 在這種模型中,每個內核級線程有一個可以輪流使用的用戶級線程集合

 

 

 

posix線程調度是一個混合模型,很靈活,足以在標准的特定實現中支持用戶級和內核級的線程。模型中包括兩級調度–線程及和內核實體級。線程級與用戶級線程類似,內核實體由內核調度。由線程庫來決定它需要多少內核實體,以及他們是如何映射的。

POSIX 引入了一個線程調度競爭范圍(thread-scheduling contention scope)的概念,這個. 概念賦予了程序員一些控制權,使它們可以控制怎樣將內核實體映射為線程。線程的contentionscope屬性可是PTHREAD_SCOPE_PROCESS,也可以是PTHREAD_SCOPE_SYSTEM。帶有PTHREAD_SCOPE_PROCESS屬性的線程與它所在的進程中的其他線程競爭處理器資源。帶有PTHREAD_SCOPE_SYSTEM屬性的線程很像內核級線程,他們在全系統的范圍內競爭處理器資源。POSIX的一種映射方式將PTHREAD_SCOPE_SYSTEM線程和內核實體之間綁定起來。

內核級線程創建時先設置線程屬性PTHREAD_SCOPE_SYSTEM,代碼如下,:

pthread_attr_t attr;

pthread_attr_init(&attr);
pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); //設置內核級的線程,以獲取較高的響應速度
//創建線程

ret = pthread_create(&iAcceptThreadId, &attr, AcceptThread, NULL);

POSIX的標准中定義了兩個值:

PTHREAD_SCOPE_SYSTEM和PTHREAD_SCOPE_PROCESS,前者表示與系統中所有線程一起競爭CPU時間,后者表示僅與同進程中的線程競爭CPU

默認為PTHREAD_SCOPE_PROCESS。目前LinuxThreads僅實現了PTHREAD_SCOPE_SYSTEM一值。

關於線程的綁定,牽涉到另外一個概念:輕進程(LWP:Light Weight Process)。輕進程可以理解為內核線程,它位於用戶層和系統層之間。系統對線程資源的分配、對線程的控制是通過輕進程來實現的,一個輕進程可以控制一個或多個線程。默認狀況下,啟動多少輕進程、哪些輕進程來控制哪些線程是由系統來控制的,這種狀況即稱為非綁定的。綁定狀況下,則顧名思義,即某個線程固定的”綁”在一個輕進程之上。被綁定的線程具有較高的響應速度,這是因為CPU時間片的調度是面向輕進程的,綁定的線程可以保證在需要的時候它總有一個輕進程可用。通過設置被綁定的輕進程的優先級和調度級可以使得綁定的線程滿足諸如實時反應之類的要求。

設置線程綁定狀態的函數為pthread_attr_setscope,它有兩個參數,第一個是指向屬性結構的指針,第二個是綁定類型,它有兩個取值:PTHREAD_SCOPE_SYSTEM(綁定的)和PTHREAD_SCOPE_PROCESS(非綁定的)。

5 用戶級線程和內核級線程的區別


內核支持線程是OS內核可感知的,而用戶級線程是OS內核不可感知的。

用戶級線程的創建、撤消和調度不需要OS內核的支持,是在語言(如Java)這一級處理的;而內核支持線程的創建、撤消和調度都需OS內核提供支持,而且與進程的創建、撤消和調度大體是相同的。

用戶級線程執行系統調用指令時將導致其所屬進程被中斷,而內核支持線程執行系統調用指令時,只導致該線程被中斷。

在只有用戶級線程的系統內,CPU調度還是以進程為單位,處於運行狀態的進程中的多個線程,由用戶程序控制線程的輪換運行;在有內核支持線程的系統內,CPU調度則以線程為單位,由OS的線程調度程序負責線程的調度。

用戶級線程的程序實體是運行在用戶態下的程序,而內核支持線程的程序實體則是可以運行在任何狀態下的程序。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM