用戶級線程與內核級線程


線程與進程

  • 進程是資源分配的基本單位,線程是調度的基本單位。
  • 進程 = 資源 + 指令執行序列,如果一個進程中有多個指令執行序列(類似多個函數),可以認為這就是多個線程。即多個線程是共享進程的資源的。通過切換線程既實現了並發,又避免了進程切換時需要切換映射表的代價。映射表實際上是用來將虛擬內存映射到真實物理內存的。
  • 因此線程的切換實質上就是映射表不變而改變PC指針。
  • 每個線程都有自己的棧,即線程棧。

線程的價值

  • 線程即多個執行序列共享一個地址空間

用戶級線程

  • 用戶級線程本質上是不經過內核的,感覺像是用自定義的函數Yield()來模擬調度,自己控制線程的切換。即用戶級線程本質上就是一系列函數集合。
  • 如上每個方框中都是一個用戶級線程的代碼,每個線程都有一個線程控制塊TCB,每個線程都有自己的函數調用棧,棧的地址就存放在線程TCB.esp中。
  • 從第一個線程,即地址100開始執行,執行到函數B則把下一個地址104壓入線程1的函數棧
  • 然后跳轉到B開始執行,執行到Yield函數開始切換線程,如圖中Yield函數的定義,注意esp是函數棧頂指針寄存器,即當前函數執行結束后會接着執行esp出棧的地址。圖中示意的是線程2中的Yield函數,從線程2切換到線程1需要做兩個操作,第一步是將當前棧頂指針寄存器esp中的內容保存到線程2的TCB中,即TCB2.esp中。第二步是將線程1的TCB1.esp放到cpu的寄存器esp中。即用戶級線程的切換本質上就是切換TCB和每個線程的棧(也在TCB中存着)。
  • 注意圖中線程2的Yield函數中藍線圈出來的部分需要刪除,因為不需要手動跳轉到204,只要函數Yield執行完畢(到右括號),棧頂指針寄存器就會執行出棧,並從出棧元素處開始執行,此時棧頂指針寄存器中的棧頂元素就是204,因此可以直接從204開始執行。換言之,如果在Yield中jmp語句不刪去,那么會先跳轉到204處執行,然后將線程1的B函數執行完畢后會接着從執行函數棧頂元素處的代碼,此時棧頂是204,,,於是相當於執行了兩個204處的代碼。
  • 用戶級線程不經過內核,少了進出內核的消耗,因此效率較高,但是如果某個線程要與硬件交互,比如網卡IO,則會引起對應的進程阻塞,此時cpu不會切換到其它線程去執行,而是直接切換到了另一個進程,如果此時沒有其它進程,則直接導致cpu空轉。因此即使通過用戶級線程啟動了多個任務序列,但一旦在內核中阻塞了,則啟動這多個序列的並發性就沒有了效果。
  • 內核級線程的TCB都在內核中,因此不用自己寫Yield,而是由操作系統自動調度。

內核級線程

  • 內核級線程能更好利用多核處理器,多核與多CPU的區別如下,多CPU有多個緩存和MMU,多核處理器則是使用同一套緩存和MMU。內核級線程中各個線程可以執行在不同的核上,從而實現並行。並發是同時出發交替執行,並行則是同時執行。

  • 內核級線程相比用戶級線程的本質區別有兩點,一點是內核級線程的TCB在內核中,由內核負責切換。第二點是兩個用戶級線程需要兩個用戶(函數)棧,而兩個內核級線程則需要使用兩套棧,即每個TCB包含兩個棧,一個用戶棧一個內核棧,當切換核心機線程即切換TCB時會同時切換用戶棧和內核棧,不過這都是操作系統的活啦。

  • 用戶線程通過中斷陷入內核,然后把用戶棧的一些相關信息壓入內核棧,內核線程通過IRET指令返回用戶態,並將內核棧中的相關信息出棧。

內核級線程切換5段論

  • 因為本質上我們寫的程序都是應用程序,只有遇到跟硬件交互等任務時才會陷入內核,因此五段論最開始都是在用戶棧開始的。
  • 第一段,用戶態程序調用中斷,進入切換。
  • 第二段,中斷處理,比如啟動磁盤讀或時鍾中斷等,這會引發TCB切換,即線程切換。
  • 第三段,tcb切換,從一個線程到另一個線程。
  • 第四段,內核棧切換,從一個線程的內核棧,切換另一個線程的內核棧。
  • 第五段,中斷出口,從內核棧切換回用戶棧。
  • 在用戶看來,就是兩個線程的切換,內核中內核棧的切換是操作系統完成的,具體細節不可見。

用戶級線程與內核級線程的對比


免責聲明!

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



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