使用者態執行緒和核心態執行緒是怎麼進行繫結的,具體程式碼是怎麼實現的?
手寫一個使用者態網路協議棧,瞬間提升你網路功底
更多知識影片:C/C++Linux伺服器開發/後臺架構師-學習影片教程
系統不排程使用者態執行緒,但是使用者態執行緒,都是寄生在系統執行緒上,而且不是一一對應的關係,可以有多個使用者態執行緒,共用一個系統執行緒。
試著簡單說一下。
使用者態執行緒和核心態執行緒概念應該出現在討論不同作業系統對於“執行緒”概念的不同實現中。一般來說有核心態與使用者態1:1,1:N,M:N三種模型,分別對應不同的實現與排程策略。例如在1:N模型中,一個核心執行緒對應多個使用者執行緒,當作業系統排程至這個核心執行緒時,需要一個“執行緒庫”中間層負責N個使用者態執行緒的排程。
對於Linux而言,採用的是1:1的模型。如果能理解多程序的排程,那麼多執行緒的排程策略與多程序幾乎是一致的。這一點從linux建立多執行緒系統呼叫clone() ,以及多程序系統呼叫fork() (實際上是利用clone() 實現的)的一致性可以看出,兩者的不同主要在於對記憶體空間等資源的繼承/共享方式有些不同。
作業系統負責排程的程序/執行緒是幾乎等價的排程實體
很是能理解樓主的困惑,因為當初自己學作業系統的時候也思考過這個問題。這裡先建議找本作業系統的書(比如下面這本綠皮恐龍書)來學習下程序和執行緒的基本概念。
operating system concepts
從概念上來說,使用者執行緒執行在核心之上的,由使用者執行緒庫自行進行管理,而核心執行緒則由作業系統直接支援和管理。所以,使用者執行緒要執行在核心之上,則必須和核心執行緒存在某種對應關係,這種對應關係可以分為:many-to-one, one-to-one和many-to-many。
many-to-one
one-to-one
many-to-many
以many-to-many為例,在實現上需要在使用者執行緒和核心執行緒之間提供稱為輕量級程序(lightweight process, LWP)的中間資料結構。 對於使用者執行緒庫而言,LWP就像是一個虛擬處理器,應用程式可以在其上排程使用者執行緒執行。每個LWP和一個核心執行緒關聯,而對應的核心執行緒是在由作業系統排程,執行在物理處理器的。如果核心執行緒阻塞(例如在等待I/O操作完成時),LWP也會阻塞,處於呼叫鏈的上的LWP的使用者級執行緒也會阻塞。
Lightweight process (LWP)
由於執行緒有許多不同的程式碼實現,可以著重瞭解一種實現,例如在Linux系統上的實現,可以瀏覽下面這本藍色的LKD。
linux kernel development
從實現上來說,Linux採用的是one-to-one的模型,Linux是沒有執行緒的概念,所謂的執行緒實際上是被實現為標準的程序。Liunx核心不提供任何特殊的排程資訊和資料結構來表示執行緒。執行緒
本質
上就是一個程序,只不過該程序和其他程序共享某些資源。這一點可以從Linux“執行緒”的建立和普通程序的建立上得到驗證。程序在核心由對應的
task_struct
資料結構表示。建立執行緒呼叫的
clone()
函式不過是指定了建立的新的程序中父子程序共享了更多的資源,如地址空間、檔案資源、檔案描述符和訊號處理函式。
//fork()
clone
(
SIGCHLD
,
0
);
//vfork()
clone
(
CLONE_VFORK
|
CLONE_VM
|
SIGCHLD
,
0
);
// for thread
clone
(
CLONE_VM
|
CLONE_FS
|
CLONE_FILES
|
CLONE_SIGHAND
,
0
);
建議看下golang的runtime程式碼,難度不大。