用戶態(tài)和內(nèi)核態(tài)-用戶線程和內(nèi)核態(tài)線程的區(qū)別
前言
用戶態(tài)和內(nèi)核態(tài):用戶線程和內(nèi)核態(tài)線程有什么區(qū)別?
面試題:用戶態(tài)和內(nèi)核態(tài):用戶線程和內(nèi)核態(tài)線程有什么區(qū)別?
組合型問題:
- 用戶態(tài)和內(nèi)核態(tài)是什么?
- 用戶級線程和內(nèi)核線程是怎樣的對應(yīng)關(guān)系?
- 內(nèi)核相應(yīng)系統(tǒng)調(diào)用是怎樣的過程?
- ......
而且這個問題還關(guān)聯(lián)到了我們后面要學(xué)習(xí)的多線程、I/O 模型、網(wǎng)絡(luò)優(yōu)化等。 所以這是一道很不錯的面試題目,它不是簡單考某個概念,而是通過讓求職者比較兩種東西,從而考察你對知識整體的認知和理解。 今天就請你順著這個問題,深入學(xué)習(xí)內(nèi)核的工作機制,和我一起去理解用戶態(tài)和內(nèi)核態(tài)。
一.什么是用戶態(tài)和內(nèi)核態(tài)?
Kernel運行在超級權(quán)限模式(Supervisor Mode)下,所以擁有很高的權(quán)限,按照權(quán)限管理原則,多數(shù)應(yīng)用程序應(yīng)該運行在最小權(quán)限下,因此很多操作系統(tǒng)將內(nèi)存分為2個區(qū)域:
- 內(nèi)核空間:只有內(nèi)核程序可以訪問
- 用戶空間:專門給應(yīng)用程序使用
二.用戶態(tài)和內(nèi)核態(tài)
用戶空間中的代碼被限制了只能使用一個局部的內(nèi)存空間,我們說這些程序在用戶態(tài)(User Mode)執(zhí)行。內(nèi)核空間中的代碼可以訪問所有內(nèi)存,我們稱這些程序在內(nèi)核態(tài)(Kernal Mode) 執(zhí)行。
三.系統(tǒng)調(diào)用過程
如果用戶態(tài)程序需要執(zhí)行系統(tǒng)調(diào)用,就需要切換到內(nèi)核態(tài)執(zhí)行。下面我們來講講這個過程的原理。
如上圖所示:內(nèi)核程序執(zhí)行在內(nèi)核態(tài)(Kernal Mode),用戶程序執(zhí)行在用戶態(tài)(User Mode)。當發(fā)生系統(tǒng)調(diào)用時,用戶態(tài)的程序發(fā)起系統(tǒng)調(diào)用。因為系統(tǒng)調(diào)用中牽扯特權(quán)指令,用戶態(tài)程序權(quán)限不足,因此會中斷執(zhí)行,也就是 Trap(Trap 是一種中斷)。
發(fā)生中斷后,當前 CPU 執(zhí)行的程序會中斷,跳轉(zhuǎn)到中斷處理程序。內(nèi)核程序開始執(zhí)行,也就是開始處理系統(tǒng)調(diào)用。內(nèi)核處理完成后,主動觸發(fā) Trap,這樣會再次發(fā)生中斷,切換回用戶態(tài)工作。
四.線程模型
上面我們學(xué)習(xí)了用戶態(tài)和內(nèi)核態(tài),接下來我們從進程和線程的角度進一步思考本課時開頭拋出的問題。
1.進程和線程
一個應(yīng)用程序啟動后會在內(nèi)存中創(chuàng)建一個執(zhí)行副本,這就是進程。Linux 的內(nèi)核是一個 MonolithicKernel(宏內(nèi)核),因此可以看作一個進程。也就是開機的時候,磁盤的內(nèi)核鏡像被導(dǎo)入內(nèi)存作為一個執(zhí)行副本,成為內(nèi)核進程
進程可以分成用戶態(tài)進程和內(nèi)核態(tài)進程兩類。用戶態(tài)進程通常是應(yīng)用程序的副本,內(nèi)核態(tài)進程就是內(nèi)核本身的進程。如果用戶態(tài)進程需要申請資源,比如內(nèi)存,可以通過系統(tǒng)調(diào)用向內(nèi)核申請。 那么用戶態(tài)進程如果要執(zhí)行程序,是否也要向內(nèi)核申請呢? 程序在現(xiàn)代操作系統(tǒng)中并不是以進程為單位在執(zhí)行,而是以一種輕量級進程(Light WeightedProcess),也稱作線程(Thread)的形式執(zhí)行。一個進程可以擁有多個線程。進程創(chuàng)建的時候,一般會有一個主線程隨著進程創(chuàng)建而創(chuàng)建
如果進程想要創(chuàng)造更多的線程,就需要思考一件事情,這個線程創(chuàng)建在用戶態(tài)還是內(nèi)核態(tài)。你可能會問,難道不是用戶態(tài)的進程創(chuàng)建用戶態(tài)的線程,內(nèi)核態(tài)的進程創(chuàng)建內(nèi)核態(tài)的線程嗎?其實不是,進程可以通過 API 創(chuàng)建用戶態(tài)的線程,也可以通過系統(tǒng)調(diào)用創(chuàng)建內(nèi)核態(tài)的線程,接下來我們說說用戶態(tài)的線程和內(nèi)核態(tài)的線程。
2.用戶態(tài)線程
用戶態(tài)線程也稱作用戶級線程(User Level Thread)。操作系統(tǒng)內(nèi)核并不知道它的存在,它完全是在用戶空間中創(chuàng)建。 用戶級線程有很多優(yōu)勢,比如。
- 管理開銷?。?/strong>創(chuàng)建、銷毀不需要系統(tǒng)調(diào)用。
- 切換成本低:用戶空間程序可以自己維護,不需要走操作系統(tǒng)調(diào)度。
但是這種線程也有很多的缺點
- 與內(nèi)核協(xié)作成本高:比如這種線程完全是用戶空間程序在管理,當它進行 I/O 的時候,無法利用到內(nèi)核的優(yōu)勢,需要頻繁進行用戶態(tài)到內(nèi)核態(tài)的切換。
- 線程間協(xié)作成本高:設(shè)想兩個線程需要通信,通信需要 I/O,I/O 需要系統(tǒng)調(diào)用,因此用戶態(tài)線程需要支付額外的系統(tǒng)調(diào)用成本。
- 無法利用多核優(yōu)勢:比如操作系統(tǒng)調(diào)度的仍然是這個線程所屬的進程,所以無論每次一個進程有多少用戶態(tài)的線程,都只能并發(fā)執(zhí)行一個線程,因此一個進程的多個線程無法利用多核的優(yōu)勢。
- 操作系統(tǒng)無法針對線程調(diào)度進行優(yōu)化:當一個進程的一個用戶態(tài)線程阻塞(Block)了,操作系統(tǒng)無法及時發(fā)現(xiàn)和處理阻塞問題,它不會更換執(zhí)行其他線程,從而造成資源浪費。
3.內(nèi)核態(tài)線程
內(nèi)核態(tài)線程也稱作內(nèi)核級線程(Kernel Level Thread)。這種線程執(zhí)行在內(nèi)核態(tài),可以通過系統(tǒng)調(diào)用創(chuàng)造一個內(nèi)核級線程。 內(nèi)核級線程有很多優(yōu)勢。
- 可以利用多核 CPU 優(yōu)勢:內(nèi)核擁有較高權(quán)限,因此可以在多個 CPU 核心上執(zhí)行內(nèi)核線程。
- 操作系統(tǒng)級優(yōu)化:內(nèi)核中的線程操作 I/O 不需要進行系統(tǒng)調(diào)用;一個內(nèi)核線程阻塞了,可以立即讓另一個執(zhí)行。
當然內(nèi)核線程也有一些缺點。
- 創(chuàng)建成本高:創(chuàng)建的時候需要系統(tǒng)調(diào)用,也就是切換到內(nèi)核態(tài)。
- 擴展性差:由一個內(nèi)核程序管理,不可能數(shù)量太多。
- 切換成本較高:切換的時候,也同樣存在需要內(nèi)核操作,需要切換內(nèi)核態(tài)。
五.用戶態(tài)線程和內(nèi)核態(tài)線程之間的映射關(guān)系
線程簡單理解,就是要執(zhí)行一段程序。程序不會自發(fā)的執(zhí)行,需要操作系統(tǒng)進行調(diào)度。我們思考這樣一個問題,如果有一個用戶態(tài)的進程,它下面有多個線程。如果這個進程想要執(zhí)行下面的某一個線程,應(yīng)該如何做呢?
這時,比較常見的一種方式,就是將需要執(zhí)行的程序,讓一個內(nèi)核線程去執(zhí)行。畢竟,內(nèi)核線程是真正的線程。因為它會分配到 CPU 的執(zhí)行資源。
如果一個進程所有的線程都要自己調(diào)度,相當于在進程的主線程中實現(xiàn)分時算法調(diào)度每一個線程,也就是所有線程都用操作系統(tǒng)分配給主線程的時間片段執(zhí)行。這種做法,相當于操作系統(tǒng)調(diào)度進程的主線程;進程的主線程進行二級調(diào)度,調(diào)度自己內(nèi)部的線程。 這樣操作劣勢非常明顯,比如無法利用多核優(yōu)勢,每個線程調(diào)度分配到的時間較少,而且這種線程在阻塞場景下會直接交出整個進程的執(zhí)行權(quán)限。 由此可見,用戶態(tài)線程創(chuàng)建成本低,問題明顯,不可以利用多核。內(nèi)核態(tài)線程,創(chuàng)建成本高,可以利用多核,切換速度慢。因此通常我們會在內(nèi)核中預(yù)先創(chuàng)建一些線程,并反復(fù)利用這些線程。這樣,用戶態(tài)線程和內(nèi)核態(tài)線程之間就構(gòu)成了下面 4 種可能的關(guān)系:
1.多對一(Many to One)
用戶態(tài)進程中的多線程復(fù)用一個內(nèi)核態(tài)線程。這樣,極大地減少了創(chuàng)建內(nèi)核態(tài)線程的成本,但是線程不可以并發(fā)。因此,這種模型現(xiàn)在基本上用的很少。我再多說一句,這里你可能會有疑問,比如:用戶態(tài)線程怎么用內(nèi)核態(tài)線程執(zhí)行程序? 程序是存儲在內(nèi)存中的指令,用戶態(tài)線程是可以準備好程序讓內(nèi)核態(tài)線程執(zhí)行的。后面的幾種方式也是利用這樣的方法。
2.一對一(One to One)
該模型為每個用戶態(tài)的線程分配一個單獨的內(nèi)核態(tài)線程,在這種情況下,每個用戶態(tài)都需要通過系統(tǒng)調(diào)用創(chuàng)建一個綁定的內(nèi)核線程,并附加在上面執(zhí)行。 這種模型允許所有線程并發(fā)執(zhí)行,能夠充分利用多核優(yōu)勢,Windows NT 內(nèi)核采取的就是這種模型。但是因為線程較多,對內(nèi)核調(diào)度的壓力會明顯增加。
3.多對多(Many to Many)
這種模式下會為 n 個用戶態(tài)線程分配 m 個內(nèi)核態(tài)線程。m 通??梢孕∮?n。一種可行的策略是將 m 設(shè)置為核數(shù)。這種多對多的關(guān)系,減少了內(nèi)核線程,同時也保證了多核心并發(fā)。Linux 目前采用的就是該模型。
4.兩層設(shè)計(Two Level)
這種模型混合了多對多和一對一的特點。多數(shù)用戶態(tài)線程和內(nèi)核線程是 n 對 m 的關(guān)系,少量用戶線程可以指定成 1 對 1 的關(guān)系。
上圖所展現(xiàn)的是一個非常經(jīng)典的設(shè)計。
六.總結(jié)
我們這節(jié)課講解的問題、考慮到的情況以及解決方法,將為你今后解決實際工作場景中的問題打下堅實的基礎(chǔ)。比如處理并發(fā)問題、I/O 性能瓶頸、思考數(shù)據(jù)庫連接池的配置等,要想完美地解決問題,就必須掌握這些模型,了解問題的本質(zhì)上才能更好地思考問題衍生出來的問題。
這節(jié)課我們學(xué)習(xí)了用戶態(tài)和內(nèi)核態(tài),然后我們簡單學(xué)習(xí)了進程和線程的基礎(chǔ)知識。 最后,我們還討論了用戶線程和內(nèi)核線程的映射關(guān)系,這是一種非常經(jīng)典的設(shè)計和思考方式。關(guān)于這個場景我們討論了 1 對 1、1 對多以及多對 1,兩層模型 4 種方法。日后你在處理線程池對接;遠程 RPC調(diào)用;消息隊列時,還會反復(fù)用到今天的方法。 那么通過這節(jié)課的學(xué)習(xí),你現(xiàn)在是否可以來回答本節(jié)關(guān)聯(lián)的面試題目?用戶態(tài)線程和內(nèi)核態(tài)線程的區(qū)別?老規(guī)矩,請你先在腦海里構(gòu)思下給面試官的表述,并把你的思考寫在留言區(qū),然后再來看我接下來的分析。 【解析】 用戶態(tài)線程工作在用戶空間,內(nèi)核態(tài)線程工作在內(nèi)核空間。用戶態(tài)線程調(diào)度完全由進程負責(zé),通常就是由進程的主線程負責(zé)。相當于進程主線程的延展,使用的是操作系統(tǒng)分配給進程主線程的時間片段。內(nèi)核線程由內(nèi)核維護,由操作系統(tǒng)調(diào)度。 用戶態(tài)線程無法跨核心,一個進程的多個用戶態(tài)線程不能并發(fā),阻塞一個用戶態(tài)線程會導(dǎo)致進程的主線程阻塞,直接交出執(zhí)行權(quán)限。這些都是用戶態(tài)線程的劣勢。內(nèi)核線程可以獨立執(zhí)行,操作系統(tǒng)會分配時間片段。因此內(nèi)核態(tài)線程更完整,也稱作輕量級進程。內(nèi)核態(tài)線程創(chuàng)建成本高,切換成本高,創(chuàng)建太多還會給調(diào)度算法增加壓力,因此不會太多。 實際操作中,往往結(jié)合兩者優(yōu)勢,將用戶態(tài)線程附著在內(nèi)核態(tài)線程中執(zhí)行。
七.思考題
最后我再給你出一道需要查資料的思考題:JVM 的線程是用戶態(tài)線程還是內(nèi)核態(tài)線程?
到此這篇關(guān)于用戶態(tài)和內(nèi)核態(tài)-用戶線程和內(nèi)核態(tài)線程的區(qū)別的文章就介紹到這了,更多相關(guān)用戶線程和內(nèi)核態(tài)線程區(qū)別內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Windows 10系統(tǒng)安裝虛擬專用網(wǎng)客戶端工具(圖文教程)
本文通過圖文并茂的形式給大家介紹了Windows 10系統(tǒng)安裝虛擬專用網(wǎng)客戶端工具,非常不錯,具有一定的參考借鑒價值,需要的朋友參考下吧2019-11-11華為鴻蒙DevEco studio2.0的安裝和hello world運行教程
這篇文章主要介紹了關(guān)于華為鴻蒙DevEco studio2.0的安裝和運行第一個hello world的文章教程詳解,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧2020-09-09man -f/-k [keyword]在fedora 29 中報錯nothing appropriate
這篇文章主要介紹了man -f/-k [keyword]在fedora 29 中報錯nothing appropriate ,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下2019-04-04windows下使用Xshell時出現(xiàn)丟失msvcr110.dll等dll問題
這篇文章主要介紹了windows下使用Xshell時出現(xiàn)丟失msvcr110.dll等dll問題,本文給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下2019-04-04