執行緒與並行模型

使用者層級執行緒(user-level threads)

想像一位經理自己保有一張私人待辦清單,安靜地在自己的桌前在各項工作之間切換,從不告訴總公司他正在做哪一項任務。總公司只看到一位忙碌的員工,從不介入這些切換。使用者層級執行緒就像這樣:完全由你程式裡的一個函式庫在使用者空間建立並管理的執行緒,作業系統核心對它們一無所知。在核心眼中,整個行程只是一條執行流。

具體來說,使用者層級執行緒函式庫住在你的程式裡,自己維護一張執行緒表,每條執行緒都有自己存好的堆疊與暫存器。當一條執行緒該讓位給另一條時,這個函式庫自己在使用者模式下完成切換,存下一條執行緒的暫存器、載入下一條,不需要系統呼叫、不必進入核心。因為這一切都不用進出核心,建立執行緒與在執行緒之間切換都極快、極便宜。決定下一條使用者執行緒由誰跑的是這個函式庫,而不是作業系統的排程器,所以程式可以使用為自己量身打造的排程策略。

取捨正是每位初學者必須學會的關鍵。由於核心只看到一個可排程的個體,會帶來兩個後果。第一,如果任何一條使用者執行緒做了會阻塞的系統呼叫(例如從緩慢的磁碟讀取),核心會把整個行程都阻塞住,其他每一條使用者執行緒也跟著凍結,因為核心根本不知道它們存在、無從改排其他東西。第二,這個行程一次只能在一個 CPU 核心上執行,所以單靠使用者層級執行緒只能得到並行,得不到真正的平行。這些限制正是為什麼純使用者層級執行緒通常要搭配核心支援(多對多模型),或者在真正需要平行時改用一對一執行緒。

一個老式的協作式執行緒函式庫可以讓你幾乎零成本地產生上千條使用者層級執行緒,並在奈秒之間於它們之間切換。但一旦其中某條對緩慢的檔案呼叫了會阻塞的 read(),其餘所有執行緒都會卡死,直到那個讀取回來為止,因為核心把整個行程都停住了,根本不知道其他執行緒正等著要跑。

快又便宜,但對核心隱形,一個阻塞呼叫就讓它們全部凍結。

單靠使用者層級執行緒無法使用多個核心,而且一個會阻塞的系統呼叫就可能讓行程裡每一條執行緒停擺。它們的速度恰恰來自於不進入核心。

又称
user threadsuser-space threads使用者執行緒使用者空間執行緒