进程线程006 Windows线程切换-线程优先级
文章目錄
- 內容回顧
- 調度鏈表
- 如何高效查找
- 如果沒有就緒線程怎么辦
內容回顧
之前我們已經了解過,有三種情況會導致線程切換:
KiSwapContext和KiQuantumEnd函數中都是通過KiFindReadyThread來找下一個要切換的線程,這次要解決的問題是KiFindReadyThread是根據什么條件來選擇下一個要執行的線程。
調度鏈表
kd> dd KiDispatcherReadyListHead 8055bc20 8055bc20 8055bc20 8055bc28 8055bc28 8055bc30 8055bc30 8055bc30 8055bc38 8055bc38 8055bc40 8055bc40 8055bc40 8055bc48 8055bc48 8055bc50 8055bc50 8055bc50 8055bc58 8055bc58 8055bc60 8055bc60 8055bc60 8055bc68 8055bc68 8055bc70 8055bc70 8055bc70 8055bc78 8055bc78 8055bc80 8055bc80 8055bc80 8055bc88 8055bc88 8055bc90 8055bc90 8055bc90 8055bc98 8055bc98線程的調度鏈表一共有32個,這32個是按照不同的級別存放在一起的。例如線程級別為0的掛到0號鏈表里,線程級別為1的掛到1號鏈表里。
KiFindReadyThread查找線程的方式—>按照優先級進行查找:31…30…29…28。也就是說,在本次查找中,如果級別31的鏈表里面有線程,那么就不會查找級別為30的鏈表
這并不意味著線程級別高的線程執行完了才能執行線程級別低的線程,在查找的時候,每次只會查找線程級別最高的那個線程,但是高級別的線程在執行的時候,如果調用了API或者CPU時間片到期,低級別的線程仍然是有機會執行的。
如何高效查找
調度鏈表有32個,每次從頭查找效率太低,所以Windows在這方面做了一個優化。
Windows定義了一個DWORD類型的變量來記錄:
DWORD類型的變量有32位,里面的每一位分別對應當前某一個鏈表里面是否有正在等待調度的線程。
當向調度鏈表中掛入或者刪除某個線程的時候,會判斷當前級別的鏈表是否為空,為空則將DWORD變量對應位置置0,否則置1
當某一個時刻,這個DWORD類型的變量轉換為二進制的值如上圖的時候,意味著在32個鏈表里,線程級別為30的鏈表里有等待調度的線程,線程級別為29的鏈表里也是有等待調度的線程。其他的鏈表則沒有等待調度的線程。
這個變量:_kiReadySummary
如果沒有就緒線程怎么辦
在KPCR里面有一個子結構體PrcbData,這個子結構體有三個重要的成員,如下
PrcbData: +0x004 CurrentThread : Ptr32 _KTHREAD +0x008 NextThread : Ptr32 _KTHREAD +0x00c IdleThread : Ptr32 _KTHREAD- CurrentThread:當前正在運行的線程
- NextThread:下一次準備運行的線程,也就是備用線程
- IdleThread:空閑線程,當前的CPU查找調度鏈表發現里面已經沒有需要調度的線程的時候,就會運行這個線程
下面通過代碼論證,首先找到KiFindReadyThread
交叉引用找到上一層調用它的函數,以KiSwapThread為例
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-wl5LlG80-1581510940435)(assets/1581478367459.png)]
這里調用了KiFindReadyThread查找一個就緒線程,然后判斷是否為空,如果為空則繼續往下執行
.text:00429162 mov eax, [esi+0Ch]這里的esi就是PrcbData結構體,+0xC的位置就是IdleThread,這里取出IdleThread放到eax里
.text:0042916C or _KiIdleSummary, edx接著修改這個全局變量
然后繼續調用KiSwapContext進行線程切換,這個時候切換的目標線程就是IdleThread
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的进程线程006 Windows线程切换-线程优先级的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 进程线程005 SwapContext函
- 下一篇: 进程线程007 进程挂靠与跨进程读写内存