Windows核心編程學習筆記(14)--進程和線程的優先級

Drecik學習經驗分享

轉載請註明出處:http://blog.csdn.net/drecik__/article/details/8095467

 

1. 進程優先級

Windows支持6個優先級類,從小到大分別爲:idle,blow normal,normal,above normal,high,real-time。其中normal是在ui常用的優先級類,爲99%的用戶使用。

  • real-time:此進程中的線程必須立即響應事件,執行實時任務,此進程中的線程還會搶佔操作系統組件的CPU時間,使用需極爲小心。
  • high:此進程中的線程必須立即響應事件,執行實時任務,任務管理器運行在這一級,所以可以通過它結束失控的進程。
  • above normal:此進程的線程運行在normal和high之間。
  • normal:此進程中的線程無需特殊的調度。
  • below normal:此進程中的線程運行在normal和idle之間。
  • idle:此進程中的線程在系統空閒時運行,屏幕保護程序,後臺使用程序和統計數據收集軟件通常使用該進程。

只有在絕對必要的時候才使用high優先級類,應該極可能避免使用real-time優先級類,因爲real-time的進程會搶佔操作系統組件的CPU時間,可能會阻止必要的磁盤I/O和網絡通信,而且鍵盤和鼠標輸入也無法及時的處理,只有充分的理由才使用real-time優先級。

注意:進程優先級的只是一個概念,進程是無法調度的,能調度的只有線程。

2. 線程優先級

首先說下線程優先級的調度模式:

在系統中每個線程都被賦予了0(最低)~31(最高)的優先級數,當系統決定哪個線程分配時,他會以優先級從大到小的來查找可供調度的線程來給他分配CPU,所以一個線程有比它優先級更高的線程可以被調度時,將導致該線程不會被調度,我們稱這種情況飢餓(操作系統會動態的提高該線程優先級,關於動態提高優先級在後面講述)。

還有一點就是較高優先級線程總是會搶佔較低優先級的進程,無論較低優先級進程是否在執行。

順便提一下,系統啓動時,將創建一個名爲頁面清零的特殊線程,這個線程的優先級爲0,是整個系統中唯一一個優先級爲0的線程,該線程在沒有其他進程需要執行的時候,將系統內存中所有閒置內存頁面清零。

 

接下來講操作系統怎麼支持線程優先級:

Windows支持7個相對線程優先級,從小到大分別爲:idle,lowest,blow normal,normal,highest,time-critical。

注意我們這裏沒有提及0~31這個線程的優先級值,因爲應用程序開發人員無需處理這個,線程的優先級值是用進程優先級類和相對線程優先級來確定的,以下表格給出來Windows Vista這個映射的具體情況:

從表中可以清楚的看到線程的優先級值與進程優先級類和相對線程優先級有一一的映射關係,但是這個不同的windows版本可能有所不同。

3. 優先級編程

  • 進程優先級編程

進程優先級可以在CreateProcess時,給參數dwCreationFlags參數(詳情見我之前的博文)傳入需要的優先級,下面給出優先級標識符:

REALTIME_PRIORITY_CLASS

HIGH_PRIORITY_CLASS

ABOVE_NORMAL_PRIORITY_CLASS

NORMAL_PRIORITY_CLASS

BELOW_NORMAL_PRIORITY_CLASS

IDLE_PRIORITY_CLASS

根據標示符單詞可以很好的理解他們的意思,這裏不再解釋

進程運行的時候可以使用SetPriorityClass來改變優先級:

BOOL SetPriorityClass(
	HANDLE hProcess,		// 進程句柄;
	DWORD dwPriorityClass	// 優先級標識符;
	);


有了設置當然後獲得,使用GetPriorityClass獲得進程優先級:

DWORD GetPriorityClass(
	HANDLE hProcess		// 進程句柄,返回優先級標識符;
	);


最後兩種是利用操作系統軟件來改變進程優先級:

第一種是在cmd裏面啓動進程時使用START命令調用進程,在調用的時候可以指定一個優先級,例如:

c:\>START /LOW CALC.EXE

該命令以idle優先級運行一個計算器,同樣還有/BELOWNORMAL, /NROAM, /ABOVENORMAL, /HIGH, /REALTIME

第二種是使用任務管理器,右鍵單機任務管理器上面的進程,可以在設置優先級菜單中指定優先級。

  • 線程優先級編程

 線程優先級可以使用SetThreadPriority進行設置和GetThreadPriority進行獲取:

BOOL SetThreadPriority(
	HANDLE hThread,		// 線程句柄;
	int nPriority		// 優先級標識符;
	);

int GetThreadPriority(
	__in HANDLE hThread	// 線程句柄,返回優先級標識符;
	);


線程標識符可以是下列值,分別對應一個相對線程優先級:

THREAD_PRIORITY_TIME_CRITICAL

THREAD_PRIORITY_HIGHEST

THREAD_PRIORITY_ABOVE_NORMAL

THREAD_PRIORITY_NORMAL

THREAD_PRIORITY_BELOW_NORMAL

THREAD_PRIORITY_LOWEST

THREAD_PRIORITY_IDLE

注意:改變優先級的時候需要掛起線程

4. 動態提升線程優先級

系統通過線程的相對優先級加上線程所屬進程的優先級來確定線程的優先級,該優先級稱爲基本優先級。

有些時候系統會動態提升一個線程的優先級,通常是爲了響應某種I/O實現,比如窗口消息或者磁盤讀取

例如:在high優先級進程中的一個normal線程,基本優先級值爲13,如果用戶敲擊一個鍵,在該線程隊列中放入WM_KEYDOWN消息,鍵盤設備驅動程序使系統臨時提升線程的優先級,可能會提升2,變爲15。線程在優先級爲15時分的一個時間片,時間片結束後優先值減1,在下一個時間片結束後又將減1,以後將保持爲13進行執行。

注意,線程的當前優先級不會低於進程的基本優先級。

系統只提升優先級值爲1~15的線程,這個範圍被稱爲動態優先級範圍,系統不會把線程優先級值提升到實時範圍(高於15),系統也不能提升實時範圍的線程。

應用程序可以使用下面函數來獲取當前是否進行動態提升和設置是否允許動態提升:

// 對一個進程中的所有線程進行指定;
BOOL SetProcessPriorityBoost(
	HANDLE hProcess,			// 進程句柄;
	BOOL bDisablePriorityBoost	// 是否允許動態提升;
	);
BOOL SetThreadPriorityBoost(
	HANDLE hThread,				// 線程句柄;
	BOOL bDisablePriorityBoost	// 是否允許動態提升;
	);

// 同樣有獲取是否允許動態提升;
BOOL GetProcessPriorityBoost(
	HANDLE hProcess,			// 進程句柄;
	PBOOL  pDisablePriorityBoost// 返回是否允許動態提升;
	);
BOOL GetThreadPriorityBoost(
	HANDLE hThread,
	PBOOL pDisablePriorityBoost
	);


另一種情況,當一個線程已經準備好了,但是出於飢渴狀態(優先級比它高的線程正在執行),當出於這個狀態3到4秒之後,系統會動態的將該線程提升到15,並允許它運行兩個時間片,時間片結束後,線程恢復到原來的基本優先級。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章