1. 程式人生 > 其它 >使用者級執行緒與核心級執行緒

使用者級執行緒與核心級執行緒

目錄

執行緒與程序

  • 程序是資源分配的基本單位,執行緒是排程的基本單位。
  • 程序 = 資源 + 指令執行序列,如果一個程序中有多個指令執行序列(類似多個函式),可以認為這就是多個執行緒。即多個執行緒是共享程序的資源的。通過切換執行緒既實現了併發,又避免了程序切換時需要切換對映表的代價。對映表實際上是用來將虛擬記憶體對映到真實實體記憶體的。
  • 因此執行緒的切換實質上就是對映表不變而改變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切換,從一個執行緒到另一個執行緒。
  • 第四段,核心棧切換,從一個執行緒的核心棧,切換另一個執行緒的核心棧。
  • 第五段,中斷出口,從核心棧切換回使用者棧。

使用者級執行緒與核心級執行緒的對比