用戶級線程和內核級線程,你分得清嗎?

這篇文章是上一篇博客的補充,旨在把沒有講清楚的「用戶級線程和內核級線程」補充完整。但願讀者能對線程有更進一步的瞭解。算法


小白最近在學習多線程編程。編程

網上關於多線程的資料不少,小白很快就把線程的基本概念弄懂了,但關於「用戶級線程和內核級線程」的概念,她卻怎麼也搞不清楚,只好向操做系統基礎紮實的小明請教。多線程

對於小白的問題,小明總會耐心解答:「線程裏面這兩個概念確實比較難理解,我先給你講用戶級線程吧。」函數

用戶級線程

「既然你說你已經看過線程的基本概念,那我就直接跳過這一部分了。學習

好久好久以前,線程的概念是出現了,但操做系統廠商可不能直接就去修改操做系統的內核,由於對他們來講,穩定性是最重要的。貿然把未經驗證的東西加入內核,出問題了怎麼辦?因此想要驗證線程的可用性,得另想辦法。」操作系統

「我知道我知道,那些研究人員就編寫了一個關於線程的函數庫,用函數庫來實現線程!」小白得意的說:「這個我剛剛在網上看到了。」線程

「是的,他們把建立線程終止線程等功能放在了這個線程庫內,用戶就能夠經過調用這些函數來實現所須要的功能。」小明找了張紙,寫上了幾個函數:pthread_creatpthread_exitpthread_joinpthread_yield ,接着說:「這是幾個重要的函數,你應該能大概猜出這些函數的功能吧?」code

「emmmm,讓我想一想,pthread_creat 是建立一個新線程,pthread_exit 是結束線程,pthread_join 嘛,我猜是準備運行某一個線程,而後把它加進就緒隊列。最後一個函數我就不知道了。」blog

「不知道也不要緊,一會你就清楚了。」小明接着講:「要知道,剛剛咱們說的線程庫,是位於用戶空間的,操做系統內核對這個庫一無所知,因此從內核的角度看,它仍是按正常的方式管理。」隊列

小白問道:「也就是說操做系統眼裏仍是隻有進程嘍?那我用線程庫寫的一個多線程進程,只能一次在一個 CPU 核心上運行?」

小明點點頭,說:「你說的沒錯,這實際上是用戶級線程的一個缺點,這些線程只能佔用一個核,因此作不到並行加速,並且因爲用戶線程的透明性操做系統是不能主動切換線程的,換句話講,若是 A,B 是同一個進程的兩個線程的話, A 正在運行的時候,線程 B 想要運行的話,只能等待 A 主動放棄 CPU,也就是主動調用 pthread_yield 函數。」

tobe 注:對操做系統來講,用戶級線程具備不可見性,也稱透明性

「停一下,讓我想想,」小白飛速思考着小明的話,「是否是說,即便有線程庫,用戶級線程也作不到像進程那樣的輪轉調度?」

「很是正確!看來你對進程的概念很清楚嘛。不過呢,雖然不能作到輪轉調度,但用戶級線程也有他本身的好處——你能夠爲你的應用程序定製調度算法,畢竟何時退出線程你本身說了算。剛剛說了,由於操做系統只能看到進程的存在,那若是某一個線程阻塞了,你以爲會發生什麼?」

「在操做系統眼裏,是進程阻塞了,那麼整個進程就會進入阻塞態,在阻塞操做結束前,這個進程都沒法獲得 CPU 資源。那就至關於,全部的線程都被阻塞了。」小白得意的回答。

「沒錯,因此若是任由線程進行阻塞操做,進程的效率將受到很大的影響,因此在這個過程當中,出現了一個替代方案——jacket。所謂 jacket,就是把一個產生阻塞的系統調用轉化成一個非阻塞的系統調用。」

小白驚訝地問:「這怎麼作獲得?該阻塞的調用,還能變得不阻塞?」

小明答道:「我來舉個例子吧,不是直接調用一個系統 I/O 例程,而是調用一個應用級別的 I/O jacket 例程,這個 jacket 例程中的代碼會檢查而且肯定 I/O 設備是否是正忙,若是忙的話,就在用戶態下將該線程阻塞,而後把控制權交給另外一個線程。隔一段時間後再次檢查 I/O 設備。就像你說的,最後仍是會執行阻塞調用,但使用 jacket 能夠縮短被阻塞的時間。不過有些狀況下是能夠不被阻塞的,取決於具體的實現。」

小明停頓了一會,說:「用戶級線程的概念大概就這麼多,咱們接下來說內核級線程吧。」

內核級線程

「有了用戶級線程的鋪墊,內核級線程就好講多了。如今咱們知道,許多操做系統都已經支持內核級線程了。爲了實現線程,內核裏就須要有用來記錄系統裏全部線程的線程表。當須要建立一個新線程的時候,就須要進行一個系統調用,而後由操做系統進行線程表的更新。固然了,傳統的進程表也仍是有的。你想一想看,若是操做系統「看得見」線程,有什麼好處?「

小白自信的回答:「操做系統內核若是知道線程的存在,就能夠像調度多個進程同樣,把這些線程放在好幾個 CPU 核心上,就能作到實際上的並行了。」

「還有一點你沒有說到,若是線程可見,那麼假如線程 A 阻塞了,與他同屬一個進程的線程也不會被阻塞。這是內核級線程的絕對優點。」

「那內核級線程就沒有什麼缺點嗎?」

「缺點固然是有的,你想一想看,讓操做系統進行線程調度,那意味着每次切換線程,就須要「陷入」內核態,而操做系統從用戶態到內核態的轉變是有開銷的,因此說內核級線程切換的代價要比用戶級線程大。還有很重要的一點——線程表是存放在操做系統固定的表格空間或者堆棧空間裏,因此內核級線程的數量是有限的,擴展性比不上用戶級線程。」

"內核級線程就這麼點東西,我最後給你留一張圖,你要是能看得懂,就說明你理解今天的概念了。"

兩個線程模型

小白得意地說:「我固然看得懂了,謝謝小明!」


但願你在看完個人文章以後有所收穫。

感謝你的閱讀,咱們後會有期!

聲明:原創文章,未經受權,禁止轉載

相關文章
相關標籤/搜索