1. 程式人生 > >Windows Internals 筆記——線程優先級

Windows Internals 筆記——線程優先級

執行後臺 權力 vista system 令行 eas 查詢 睡眠 設備

1.每個線程都被賦予0(最低)~31(最高)的優先級數。當系統確定給哪個線程分配CPU時,它會首先查看優先級為31的線程,並以循環的方式進行調度。如果有優先級為31的線程可供調度,那麽系統就會將CPU分配給該線程。在該線程的時間片結束時,系統查看是否還存在另一個優先級為31的線程可以運行,如果存在,它將獲得CPU。

2.只要有優先級為31的線程可供調度,系統就不會給優先級0~30的線程分配CPU。這種情況稱為饑餓。在多處理器機器上饑餓發生的可能性要小得多,因為這種機器上優先級為31和30的線程可以同時運行。

3.較高優先級的線程總是會搶占較低優先級的線程,無論較低優先級的線程是否正在執行。系統確定有較高優先級的線程已經準備好可以運行時,它會立即暫停較低優先級的線程(即使後者的時間片還沒有用完),並將CPU分配給較高優先級的線程,該線程獲得一個完整的時間片。

4.系統啟動時,將創建一個名為頁面清零線程的特殊線程。這個線程的優先級定為0,而且是整個系統中唯一一個優先級為0的線程。頁面清零線程負責在沒有其他進程需要執行的時候,將系統內存中的所有閑置頁面清零。

5.Windows API在系統的調度程序之上提供了一個抽象層,因此我們不會直接調度調度程序,相反,調用的是Windows函數,它們會根據底層操作系統的版本來解釋參數。

6.Windows支持6個優先級類:

技術分享圖片

  • idle優先級類非常適合只在系統什麽都不做的時候運行的應用程序。
  • 只有在絕對必要的時候才使用high優先級。應該盡可能避免使用real-time優先級類,因為大多數操作系統線程在執行時所用的優先級類都比它低。
  • 99%的進程都是normal優先級類。
  • 進程不能運行在real-time優先級類,除非用戶有Increase Scheduling Priority特權。默認情況下,隸屬於管理員或者高級用戶組的用戶都具有這一權限。

7.Windows支持7個相對線程優先級,這些優先級是相對於進程優先級的。同樣,大多數線程使用normal優先級。

技術分享圖片

8.概括起來,進程都屬於某個優先級類,另外還可以指定進程中線程的相對線程優先級。 在不同版本的操作系統上映射(對應到0~31)是變化的。如下表是Windows Vista上的具體情況。

技術分享圖片

9.優先級0是保留給頁面清零線程。除此之外,應用程序也無法獲得一下優先級:17,18,19,20,21,27,28,29,30。但是如果編寫的是運行在內核模式的設備驅動程序,那麽我們可以獲得這些優先級。用戶模式的應用程序是不能獲得這些優先級的。

10.real-time優先級類的線程,其優先級值不能低於16。同理,非real-time優先級線程的優先級的優先級值不能高於15。

11.一般而言,有較高優先級的線程大多數時候都應是不可調度的,當這種線程要執行什麽任務時,很快就能得到CPU時間。這時,線程應該盡可能少地執行CPU指令,並重新進入睡眠,等待再次被調度。相反,優先級低的可以保持為可調度狀態,執行大量CPU指令以完成其任務。

12.調用CreateProcess時,可以在fdwCreate參數中傳入需要的優先級。

技術分享圖片

13.一旦進程運行,可以調用SetPriorityClass來改變自己的優先級。GetPrioirityClass來獲取進程優先級。

14.通過命令行界面調用程序時,程序的起始優先級時normal。但是,如果使用START命令調用程序,可以使用一個開關指定程序的起始優先級。例如:

C:\WINDOWS\system32>START /LOW CALC.EXE


15.CreateThread函數沒有為調用者提供設置新線程相對優先級的辦法。為了設置和獲取線程的相對優先級,必須調用SetThreadPriority和GetThreadPriority函數。

16.CreateThread總是創建相對線程優先級為normal的新線程。要使線程以idle優先級執行,我們需要在調用CreateThead上傳入CREATE_SUSPENDED標誌,這將阻止線程執行任何代碼。然後調用SetThreadPriority將線程改為idle相對線程優先級。接著調用ResumeThread,線程就成為可調度的了。

17.Windows並沒有提供返回線程優先級的函數,因為Microsoft保留了任何時候改變調度算法的權力。

18.偶爾,系統也會提升一個線程的優先級,通常時為了響應某種I/O事件,比如窗口消息或磁盤讀取。例如:

  • high優先級進程中的一個線程優先級為normal的線程,其基本優先級值為13.如果用戶敲一個鍵,系統會在線程的隊列中放入一個WM_KEYDOWN消息。因為有消息出現在線程的隊列中,線程就成為可調度的了。而且,鍵盤設備驅動程序將使用系統臨時提升線程的優先級。因此線程的優先級可能會提升2,從而達到15。
  • 線程在優先級為15時分得一個時間片。在該時間片結束之後系統將線程的優先級值減1,所以在下一個時間片中線程的優先級將為14.線程的第三個時間片以優先級13執行。以後的時間片將保持在13,即線程的基本優先級。

註意,線程的當前優先級不會低於線程的基本優先級。而且使線程可調度的設備驅動程序能夠決定提升的幅度,同樣,Microsoft也沒有在文檔中記錄任何一個設備驅動程序能夠將線程的優先級提升多少。因此,Microsoft可以不斷地微調動態提升,以確定最佳的總體響應性。

19.系統只提升優先級值在1~15的線程。這個範圍被稱為動態優先級範圍。而且,系統不會吧線程的優先級提升到實施範圍(高於15)。系統也不能動態提升實時範圍(16~31)的線程。

20.Microsoft增加SetProcessPriorityBoost和SetThreadPriorityBoost兩個函數,允許我們禁止系統對線程優先級進行動態提升。GetProcessPriorityBoost和GetThreadPriorityBoost來查詢。

21.當系統檢測到有線程已經處於饑餓狀態3到4秒,它會動態將饑餓線程的優先級提升到15,並允許該線程運行兩個時間片。當兩個時間片結束時,線程的優先級立即恢復到基本優先級。

22.如果用戶需要使用某個進程的窗口,這個進程就稱為前臺進程,所有其他進程稱為後臺進程。為了改進前臺進程的響應性,Windows會為前臺進程中的現初微調調度算法。系統給前臺進程的線程分配比一般情況下更多的時間片。這種微調只在前臺進程是normal優先級時才進行。如果處於其他優先級,則不會進行微調。

23.從Windows Vista開始,線程可以在進行I/O請求時設置優先級。我們可以通過調研SetThreadPriority並傳入THREAD_MODE_BACKGROUND_BEGIN來告訴Windows,線程應該發送低優先級的I/O請求。註意,這也將降低線程的CPU調度優先級。我們可以通過調用SetThreadPriority並傳入THREAD_MODE_BACKGROUND_END,讓線程進行normal優先級I/O的請求。系統不允許線程改變另一個線程的I/O優先級。

24.如果想讓進程中的所有線程都進行低優先級的I/O請求和低CPU調度,那麽我們可以調用SetPriorityClass,傳入THREAD_MODE_BACKGROUND_BEGIN標誌,相反則傳入THREAD_MODE_BACKGROUND_END。

25.在更細的粒度上,normal優先級線程還可以執行對某個文件執行後臺優先級I/O。例如SetFileInformationByHandle設置的優先級將覆蓋進程的優先級或線程。

26.如果一個low優先級線程獲得了normal優先級線程等待的鎖,則normal優先級線程可以在低優先級I/O請求完成之前運行,不等待後臺優先級線程。後臺優先級線程甚至不再進行I/O,以免出現問題。因此,應該盡量減少在normal和後臺優先級線程之間使用共享同步對象,以避免normal優先級線程為後臺優先級線程擁有的鎖而被阻塞,導致優先級逆轉。

Windows Internals 筆記——線程優先級