1. 程式人生 > >Windows核心程式設計 第七章 執行緒的排程、優先順序和親緣性(下)

Windows核心程式設計 第七章 執行緒的排程、優先順序和親緣性(下)

7.6 運用結構環境

    現在應該懂得環境結構線上程排程中所起的重要作用了。環境結構使得系統能夠記住執行緒的狀態,這樣,當下次執行緒擁有可以執行的C P U時,它就能夠找到它上次中斷執行的地方。

知道這樣低層的資料結構也會完整地記錄在 Platform SDK文件中確實使人吃驚。不過如果檢視該文件中的C O N T E X T結構,會看到下面這段文字:

    “C O N T E X T結構包含了特定處理器的暫存器資料。系統使用 C O N T E X T結構執行各種內部操作。目前,已經存在為 I n t e lM I P SA l p h aP o w e r P C處理器定義的

C O N T E X T結構。若要了解這些結構的定義,參見標頭檔案Wi n N T. h” 。

    該文件並沒有說明該結構的成員,也沒有描述這些成員是誰,因為這些成員要取決於Windows 2000在哪個C P U上執行。實際上,在Wi n d o w s定義的所有資料結構中,C O N T E X T結構是特定於C P U的唯一資料結構。

    那麼C O N T E X T結構中究竟存在哪些東西呢?它包含了主機 C P U上的每個暫存器的資料結構。在x 8 6計算機上,資料成員是E a xE b xE c xE d x等等。如果是A l p h a處理器,那麼資料成員包括I n t V 0

I n t T 0I n t T 1I n t S 0I n t R aI n t Z e r o等等。下面這個程式碼段顯示了 x86 CPU的完整的C O N T E X T結構:

typedef struct _CONTEXT {

    //

    // The flags values within this flag control the contents of

    // a CONTEXT record.

    //

    // If the context record is used as an input parameter, then

    // for each portion of the context record controlled by a flag

    // whose value is set, it is assumed that that portion of the

    // context record contains valid context. If the context record

    // is being used to modify a threads context, then only that

    // portion of the threads context will be modified.

    //

    // If the context record is used as an IN OUT parameter to capture

    // the context of a thread, then only those portions of the thread's

    // context corresponding to set flags will be returned.

    //

    // The context record is never used as an OUT only parameter.

    //

    DWORD ContextFlags;

    //

    // This section is specified/returned if CONTEXT_DEBUG_REGISTERS is

    // set in ContextFlags.  Note that CONTEXT_DEBUG_REGISTERS is NOT

    // included in CONTEXT_FULL.

    //

    DWORD   Dr0;

    DWORD   Dr1;

    DWORD   Dr2;

    DWORD   Dr3;

    DWORD   Dr6;

    DWORD   Dr7;

    //

    // This section is specified/returned if the

    // ContextFlags word contians the flag CONTEXT_FLOATING_POINT.

    //

    FLOATING_SAVE_AREA FloatSave;

    //

    // This section is specified/returned if the

    // ContextFlags word contians the flag CONTEXT_SEGMENTS.

    //

    DWORD   SegGs;

    DWORD   SegFs;

    DWORD   SegEs;

    DWORD   SegDs;

    //

    // This section is specified/returned if the

    // ContextFlags word contians the flag CONTEXT_INTEGER.

    //

    DWORD   Edi;

    DWORD   Esi;

    DWORD   Ebx;

    DWORD   Edx;

    DWORD   Ecx;

    DWORD   Eax;

    //

    // This section is specified/returned if the

    // ContextFlags word contians the flag CONTEXT_CONTROL.

    //

    DWORD   Ebp;

    DWORD   Eip;

    DWORD   SegCs;              // MUST BE SANITIZED

    DWORD   EFlags;             // MUST BE SANITIZED

    DWORD   Esp;

    DWORD   SegSs;

    //

    // This section is specified/returned if the ContextFlags word

    // contains the flag CONTEXT_EXTENDED_REGISTERS.

    // The format and contexts are processor specific

    //

    BYTE    ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION];

} CONTEXT;

    typedef CONTEXT *PCONTEXT;

    C O N T E X T結構可以分成若干個部分。C O N T E X T _ C O N T R O L包含C P U的控制暫存器,比如指令指標、堆疊指標、標誌和函式返回地址(與 x 8 6處理器不同,Alpya CPU在呼叫函式時,將該函式的返回地址放入一個暫存器中) 。C O N T E X T _ I N T E G E R用於標識C P U的整數暫存器。C O N T E X T _ F L O AT I N G _ P O I N T用於標識C P U的浮點暫存器。C O N T E X T _ S E G M E N T S用於標識C P U的段暫存器(僅為x 8 6處理器) 。CONTEXT_DEBUG_ REGISTER用於標識C P U的除錯暫存器(僅為x 8 6處理器) 。CONTEXT_EXTENDED_ REGISTERS用於標識C P U的擴充套件暫存器(僅為x 8 6處理器) 。

    Wi n d o w s實際上允許檢視執行緒核心物件的內部情況,以便抓取它當前的一組 C P U暫存器。若要進行這項操作,只需要呼叫G e t T h r e a d C o n t e x t函式:

 

    若要呼叫該函式,只需指定一個C O N T E X T結構,對某些標誌(該結構的C o n t e x t F l a g s成員)進行初始化,指明想要收回哪些暫存器,並將該結構的地址傳遞給 G e t T h r e a d C o n t e x t。然後該函式將資料填入你要求的成員。

    在呼叫G e t T h r e a d C o n t e x t函式之前,應該呼叫S u s p e n d T h r e a d,否則,執行緒可能被排程,而且執行緒的環境可能與你收回的不同。一個執行緒實際上有兩個環境。一個是使用者方式,一個是核心方式。G e t T h r e a d C o n t e x t只能返回執行緒的使用者方式環境。如果呼叫S u s p e n d T h r e a d來停止執行緒的執行,但是該執行緒目前正在用核心方式執行,那麼,即使 S u s p e n d T h r e a d實際上尚未暫停該執行緒的執行,它的使用者方式仍然處於穩定狀態。執行緒在恢復使用者方式之前,它無法執行更多的使用者方式程式碼,因此可以放心地將執行緒視為處於暫停狀態, G e t T h r e a d C o n t e x t函式將能正常執行。

    C O N T E X T結構的C o n t e x t F l a g s成員並不與任何C P U暫存器相對應。無論是何種 C P U結構,該成員存在於所有C O N T E X T結構定義中。C o n t e x t F l a g s成員用於向G e t T h r e a d C o n t e x t函式指明你想檢索哪些暫存器。例如,如果想要獲得執行緒的控制暫存器,可以編寫下面的程式碼:

 

    注意,在呼叫G e t T h r e a d C o n t e x t之前,首先必須對C O N T E X T結構中的C o n t e x t F l a g s成員進

行初始化。

    Wi n d o w s為程式設計人員提供了多麼強大的功能啊!如果你認為它確實不錯,那麼你一定會喜歡它的,因為Wi n d o w s使你能夠修改C O N T E X T結構中的成員,然後通過呼叫S e t T h r e a d C o n t e x t將新暫存器值放回執行緒的核心物件中:

 

    這有可能導致遠端執行緒中的訪問違規,向用戶顯示未處理的異常訊息框,同時,遠端程序終止執行。你將成功地終止另一個程序的執行,而你的程序則可以繼續很好地執行。

    G e t T h r e a d C o n t e x tS e t T h r e a d C o n t e x t函式使你能夠對執行緒進行許多方面的控制,但是在使用它們時應該小心。實際上,幾乎沒有應用程式呼叫這些函式。增加這些函式是為了增強除錯程式和其他工具的功能。任何應用程式都可以呼叫它們。

7.7 執行緒的優先順序

    本章開頭講述了C P U是如何只使執行緒執行 2 0 m s,然後排程程式將另一個可排程的執行緒分配給C P U的。如果所有執行緒具有相同的優先順序,那麼就會發生這種情況,但是,在現實環境中,執行緒被賦予許多不同的優先順序,這會影響到排程程式將哪個執行緒取出來作為下一個要執行的執行緒。

    每個執行緒都會被賦予一個從 0(最低)到3 1(最高)的優先順序號碼。當系統確定將哪個執行緒分配給C P U時,它首先觀察優先順序為3 1的執行緒,並以迴圈方式對它們進行排程。如果優先順序為3 1的執行緒可以排程,那麼就將該執行緒賦予一個C P U。在該執行緒的時間片結束時,系統要檢視是否還有另一個優先順序為3 1的執行緒可以執行,如果有,它將允許該執行緒被賦予一個C P U

    只要優先順序為3 1的執行緒是可排程的,系統就絕對不會將優先順序為 03 0的執行緒分配給C P U。這種情況稱為渴求排程(s t a r v a t i o n) 。當高優先順序執行緒使用大量的 C P U時間,從而使得低優先順序執行緒無法執行時,便會出現渴求情況。在多處理器計算機上出現渴求情況的可能性要少得多,因為在這樣的計算機上,優先順序為3 1和優先順序為3 0的執行緒能夠同時執行。系統總是設法使C P U

保持繁忙狀態,只有當沒有執行緒可以排程的時候,C P U才處於空閒狀態。

    人們可能認為,在這樣的系統中,低優先順序執行緒永遠得不到機會執行。不過正像前面指出的那樣,在任何一個時段內,系統中的大多數執行緒是不能排程的。例如,如果程序的主執行緒呼叫G e t M e s s a g e函式,而系統發現沒有執行緒可以供它使用,那麼系統就暫停程序的執行緒執行,釋放該執行緒的剩餘時間片,並且立即將C P U分配給另一個等待執行的執行緒。

    如果沒有為G e t M e s s a g e函式顯示可供檢索的訊息,那麼程序的執行緒將保持暫停狀態,並且決不會被分配給C P U。但是,當訊息被置於執行緒的佇列中時,系統就知道該執行緒不應該再處於暫停狀態。此時,如果沒有更高優先順序的執行緒需要執行,系統就將該執行緒分配給一個 C P U

現在考慮另一個問題。高優先順序執行緒將搶在低優先順序執行緒之前執行,不管低優先順序執行緒正在執行什麼。例如,如果一個優先順序為 5的執行緒正在執行,系統發現一個高優先順序的執行緒準備要執行,那麼系統就會立即暫停低優先順序執行緒的執行(即使它處於它的時間片中) ,並且將C P U分配給高優先順序執行緒,使它獲得一個完整的時間片。

    還有,當系統引導時,它會建立一個特殊的執行緒,稱為 0頁執行緒。該執行緒被賦予優先順序 0,它是整個系統中唯一的一個在優先順序0上執行的執行緒。當系統中沒有任何執行緒需要執行操作時,0頁執行緒負責將系統中的所有空閒R A M頁面置0

7.8 對優先順序的抽象說明

   M i c r o s o f t的開發人員設計執行緒排程程式時,他們發現該排程程式無法在所有時間適應所有人的需要。他們還發現,計算機的“作用”是不斷變化的。當 Windows NT問世時,物件連結和嵌入(O L E)應用程式還剛剛開始編寫。現在,O L E應用程式已經司空見慣。遊戲軟體已經相當流行。當然,在Windows NT的早期,並沒有更多地考慮I n t e r n e t的問題。

    排程演算法對使用者執行的應用程式型別有著相當大的影響。從一開始, M i c r o s o f t的開發人員就認識到,隨著系統的用途的變化,他們必須不斷修改排程演算法。但是,軟體開發人員需要在今天編寫軟體,而M i c r o s o f t則要保證軟體能夠在將來的系統版本上執行。那麼 M i c r o s o f t如何改變系統工作的方式並仍然保證軟體能夠執行呢?下面是解決這個問題的一些辦法:

Microsoft沒有將排程程式的行為特性完全固定下來。

Microsoft沒有讓應用程式充分利用排程程式的特性。

Microsoft聲稱排程程式的演算法是變化的,在編寫程式碼時應有所準備。

    Windows API展示了系統的排程程式上的一個抽象層,這樣就永遠不會直接與排程程式進行通訊。相反,要呼叫Wi n d o w s函式,以便根據執行的系統版本“轉換”引數。本章將介紹這個抽象層。

    當設計一個應用程式時, 你應該考慮到還有什麼別的應用程式會與你的應用程式一道執行。然後,應該根據你的應用程式中的執行緒應該具備何種響應性,選擇一個優先順序類。這聽起來有些費解,不過情況確實如此。M i c r o s o f t不想作出任何將來可能影響你的程式碼執行的承諾。

    Wi n d o w s支援6個優先順序類:即空閒、低於正常、正常、高於正常、高和實時。當然,正常優先順序是最常用的優先順序類, 9 9 %的應用程式均使用這個優先順序類。表 7 - 4描述了這些優先順序類。

 

    當系統什麼也不做的時候,將空閒優先順序類用於應用程式的執行是最恰當不過的。沒有用互動方式使用的計算機有可能仍然很繁忙(比如作為檔案伺服器) ,不應該與螢幕保護程式爭用C P U時間。定期更新系統的某些狀態的統計資訊跟蹤應用程式不應該干擾關鍵任務的執行。

    只有當絕對必要的時候,才可以使用高優先順序類。你會驚奇地發現, Windows Explorer是在高優先順序上執行的。大多數時間 E x p l o r e r的執行緒是暫停的,等待使用者按下操作鍵或者點選滑鼠按鈕時被喚醒。當E x p l o r e r的執行緒處於暫停狀態時,系統不將它的執行緒分配給 C P U。因為這將使低優先順序執行緒得以執行。但是一旦使用者按下一個操作鍵或組合鍵,如 C t r l + E s c,系統就會喚醒E x p l o r e r的執行緒(當用戶按下C t r l + E s c組合鍵時,也會出現S t a r t選單) 。如果低優先順序執行緒正在執行,系統會立即搶在這些執行緒的前面,讓E x p l o r e r的執行緒優先執行。

    M i c r o s o f t就是按這種方法設計E x p l o r e r的,因為使用者希望無論系統中正在執行什麼,外殼程式都具有極強的響應能力。實際上,即使低優先順序執行緒在無限迴圈中暫停執行,也能顯示E x p l o r e r的視窗。由於E x p l o r e r的執行緒擁有較高的優先順序,因此執行無限迴圈的執行緒被搶佔,E x p l o r e r讓使用者終止掛起程序的執行。E x p l o r e r的執行特性非常出色,大部分時間它的執行緒無事可做,不必佔用C P U時間。如果情況不是如此,那麼整個系統的執行速度就會慢得多,許多應用程式就不會作出響應。

    應該儘可能避免使用實時優先順序類。實際上Windows NT 3.1的早期測試版並沒有嚮應用程式展示這個優先順序類,儘管該作業系統支援這個類。實時優先順序是很高的優先順序,它可能干擾作業系統任務的執行,因為大多數作業系統執行緒均以較低的優先順序來執行。因此實時執行緒可能阻止必要的磁碟I / O資訊和網路資訊的產生。此外,鍵盤和滑鼠輸入將無法及時得到處理,使用者可能以為系統已經暫停執行。大體來說,必須有足夠的理由才能使用實時優先順序,比如需要

    以很短的等待時間來響應硬體事件,或者執行某些不能中斷的短期任務。

    注意 除非使用者擁有“提高排程優先順序”的許可權,否則程序不能用實時優先順序類來執行。凡是被指定為管理員或特權使用者的使用者,均預設擁有該許可權。

    當然,大多數程序都屬於正常優先順序類。低於正常和高於正常的優先順序類是 Windows 2000中的新增優先順序。M i c r o s o f t增加這些優先順序類的原因是,有若干家公司抱怨現有的優先順序類無法提供足夠的靈活性。

一旦選定了優先順序類之後,就不必考慮你的應用程式與其他應用程式之間的關係,只需要集中考慮你的應用程式中的各個執行緒。 Wi n d o w s支援7個相對的執行緒優先順序:即空閒、最低、低於正常、正常、高於正常、最高和關鍵時間優先順序。這些優先順序是相對於程序的優先順序類而言的。大多數執行緒都使用正常執行緒優先順序。表7 - 5描述了這些相對的執行緒優先順序。

    概括起來說,程序是優先順序類的一個組成部分,你為程序中的執行緒賦予相對執行緒優先順序。這裡沒有講到03 1的優先順序的任何情況。應用程式開發人員從來不必具體設定優先順序。相反,系統負責將程序的優先順序類和執行緒的相對優先順序對映到一個優先順序上。正是這種對映方式,M i c r o s o f t不想拘泥不變。實際上這種對映方式是隨著系統的版本的升級而變化的。

    表7 - 6顯示了這種對映方式是如何用於Windows 2000的,注意,Windows NT的早期版本和某些Windows 95Windows 98版本採用了不同的對映方式。未來的Wi n d o w s版本中的對映方式也會變化。

    例如,正常程序中的正常執行緒被賦予的優先順序是 8。由於大多數程序屬於正常優先順序類,而大多數執行緒屬於正常執行緒優先順序,因此係統中的大多數執行緒的優先順序是 8

    如果高優先順序程序中有一個正常執行緒,該執行緒的優先順序將是 1 3。如果將程序的優先順序類改為8,那麼執行緒的優先順序就變為4。如果改變了程序的優先順序類,執行緒的相對優先順序不變,但是它的優先順序的等級卻發生了變化。

 

    注意,表7 - 6並沒有顯示優先順序的等級為0的執行緒。這是因為0優先順序保留供零頁執行緒使用,系統不允許任何其他執行緒擁有 0優先順序。另外,下列優先順序等級是無法使用的: 1 71 81 92 02 12 72 82 93 0。如果編寫一個以核心方式執行的裝置驅動程式,可以獲得這些優先順序等級,而使用者方式的應用程式則不能。另外還要注意,實時優先順序類中的執行緒不能低於優先順序等級1 6。同樣,非實時優先順序類中的執行緒的等級不能高於1 5

    注意 有些人常常搞不清程序優先順序類的概念。他們認為這可能意味著程序是可以排程的。但是程序是根本不能排程的,只有執行緒才能被排程。程序優先順序類是個抽象概念,M i c r o s o f t提出這個概念的目的,是為了幫助你將它與排程程式的內部執行情況區分開來。它沒有其他目的。

    注意 一般來說,大多數時候高優先順序的執行緒不應該處於可排程狀態。當執行緒要進行某種操作時,它能迅速獲得C P U時間。這時執行緒應該儘可能少地執行 C P U指令,並返回睡眠狀態,等待再次變成可排程狀態。相反,低優先順序的執行緒可以保持可排程狀態,執行大量的C P U指令來進行它的操作。如果按照這些原則來辦,整個作業系統就能正確地對使用者作出響應。

7.9 程式的優先順序

    程序是如何被賦予優先順序類的呢?當呼叫C r e a t e P r o c e s s時,可以在f d w C r e a t e引數中傳遞需要的優先順序類。表7 - 7顯示了優先順序類的識別符號。

 

    建立子程序的程序負責選擇子程序執行的優先順序類,這看起來有點奇怪。讓我們以E x p l o r e r為例來說明這個問題。當使用E x p l o r e r來執行一個應用程式時,新程序按正常優先順序執行。E x p l o r e r不知道程序在做什麼,也不知道隔多長時間它的執行緒需要進行排程。但是,一旦子程序執行,它就能夠通過呼叫S e t P r i o r i t y C l a s s來改變它自己的優先順序類:

 

    該函式將h P r o c e s s標識的優先順序類改為f d w P r i o r i t y引數中設定的值。f d w P r i o r i t y引數可以是表7 - 7顯示的識別符號之一。由於該函式帶有一個程序控制代碼,因此,只要擁有該程序的控制代碼和足夠的訪問權,就能夠改變系統中執行的任何程序的優先順序類。

一般來說,程序將試圖改變它自己的優先順序類。下面是如何使一個程序將它自己的優先順序類設定為空閒的例子:

    SetPriorityClass(GetCurrentProcess() ,HIGH_PRIORITY_CLASS);

    下面是用來檢索程序的優先順序類的補充函式:

    DWORD GetPriorityClass(HANDLE hProcess);

    正如你所期望的那樣,該函式將返回表7 - 7中列出的識別符號之一。

    當使用命令外殼啟動一個程式時,該程式的起始優先順序是正常優先順序。但是,如果使用S t a r t命令來啟動該程式,可以使用一個開關來設定應用程式的起始優先順序。例如,在命令外殼輸入下面的命令可使系統啟動C a l c u l a t o r,並在開始時按空閒優先順序來執行它:

 

    S t a r t命令還能識別 / B E L O W N O R M A L/ N O R M A L/ A B O V E N O R M A L/ H I G H/ R E A LT I M E等開關,以便按它們各自的優先順序啟動執行一個應用程式。當然,一旦應用程式啟動執行,它就可以呼叫S e t P r i o r i t y C l a s s函式,將它自己的優先順序改為它選擇的任何優先順序。

    Windows 98 Windows 98S t a r t命令並不支援這些開關中的任何一個。Windows 98命令外殼啟動的程序總是使用正常優先順序類來執行。

    Windows 2000Task Manager使得使用者可以改變程序的優先順序類。圖 7 - 2顯示了Ta s kM a n a g e rP r o c e s s e s選項卡,它顯示了當前執行的所有程序。Base Pri列顯示了每個程序的優先順序類。可以改變程序的優先順序類,方法是選定一個程序,然後從上下文選單的 Set Priority(設定優先順序)子選單中選擇一個選項。

 

    當一個執行緒剛剛建立時,它的相對執行緒優先順序總是設定為正常優先順序。我總感到有些奇怪,C r e a t e T h r e a d沒有為呼叫者提供一個設定新執行緒的相對優先順序的方法。若要設定和獲得執行緒的相對優先順序,必須呼叫下面的這些函式:

 

    當然,h T h r e a d引數用於標識想要改變優先順序的單個執行緒, n P r i o r i t y引數是表7 - 8列出的7個識別符號之一。

 

下面是檢索執行緒的相對優先順序的補充函式:

int GetThreadPriority(HANDLE hThread);

該函式返回表7 - 8列出的識別符號之一。

若要建立一個帶有相對優先順序為空閒的執行緒,可以執行類似下面的程式碼:

 

    注意,C r e a t e T h r e a d函式建立的新函式帶有的相對優先順序總是正常優先順序。若要使執行緒以空閒優先順序來執行,應該將C R E AT E _ S U S P E N D E D標誌傳遞給C r e a t e T h r e a d函式,這可以防止執行緒執行任何程式碼。然後可以呼叫 S e t T h r e a d P r i o r i t y,將執行緒的優先順序改為相對空閒優先順序。這時可以呼叫R e s u m e T h r e a d,使得執行緒成為可排程的執行緒。你不知道執行緒何時能夠獲得 C P U時間,但是排程程式會考慮這樣一個情況,即該執行緒擁有一個空閒優先順序。最後,可以關閉新執行緒的控制代碼,一旦執行緒終止執行,核心物件就能被撤消。

    注意 Wi n d o w s沒有提供返回執行緒的優先順序的函式。這是故意進行的。記住,M i c r o s o f t保留了隨時修改排程演算法的權利。你不會設計需要排程演算法專門知識的應用程式。如果堅持使用程序優先順序類和相對執行緒優先順序,你的應用程式不僅現在能夠順利地執行,而且在系統的將來版本上也能很好地執行。

7.9.1 動態提高執行緒的優先順序等級

    通過將執行緒的相對優先順序與執行緒的程序優先順序類綜合起來考慮,系統就可以確定執行緒的優級等級。有時這稱為執行緒的 基本優先順序等級。系統常常要提高執行緒的優先順序等級,以便對視窗訊息或讀取磁碟等I / O事件作出響應。

    例如,在高優先順序類程序中的一個正常優先順序等級的執行緒的基本優先順序等級是 1 3。如果使用者按下一個操作鍵,系統就會將一個 W M _ K E Y D O W N訊息放入執行緒的佇列中。由於一個訊息已經出現線上程的佇列中,因此該執行緒就是可排程的執行緒。此外,鍵盤裝置驅動程式也能夠告訴系統暫時提高執行緒的優先順序等級。該執行緒的優先順序等級可能提高 2級,其當前優先順序等級改為1 5

    系統在優先順序為1 5時為一個時間片對該執行緒進行排程。一旦該時間片結束,系統便將執行緒的優先順序遞減1,使下一個時間片的執行緒優先順序降為 1 4。該執行緒的第三個時間片按優先順序等級1 3來執行。如果執行緒要求執行更多的時間片,均按它的基本優先順序等級 1 3來執行。

    注意,執行緒的當前優先順序等級決不會低於執行緒的基本優先順序等級。此外,導致執行緒成為可排程執行緒的裝置驅動程式可以決定優先順序等級提高的數量。 M i c r o s o f t並沒有規定各個裝置驅動程式可以給執行緒的優先順序提高多少個等級。這樣就使得 M i c r o s o f t可以不斷地調整執行緒優先順序提高的動態等級,以確定最佳的總體響應效能。

    系統只能為基本優先順序等級在 11 5之間的執行緒提高其優先順序等級。實際上這是因為這個範圍稱為動態優先順序範圍。此外,系統決不會將執行緒的優先順序等級提高到實時範圍(高於 1 5) 。由於實時範圍中的執行緒能夠執行大多數作業系統的函式,因此給等級的提高規定一個範圍,就可以防止應用程式干擾作業系統的執行。另外,系統決不會動態提高實時範圍內的執行緒優先順序等級。

    有些程式設計人員抱怨說,系統動態提高執行緒優先順序等級的功能對他們的執行緒效能會產生一種不良的影響,為此M i c r o s o f t增加了下面兩個函式,這樣就能夠使系統的動態提高執行緒優先順序等級的功能不起作用:

 

    S e t P r o c e s s P r i o r i t y B o o s t負責告訴系統啟用或停用進行中的所有執行緒的優先順序提高功能,而S e t T h r e a d P r i o r i t y B o o s t則讓你啟用或停用各個執行緒的優先順序提高功能。這兩個函式具有許多相似的共性,可以用來確定是啟用還是停用優先順序提高功能:

 

    對於這兩個函式中的每個函式,可以傳遞想要查詢的程序或執行緒的控制代碼,以及由函式設定的B O O L的地址。

       Windows 98 Windows 98沒有提供這4個函式的有用的實現程式碼。它們全部返回FA L S E,後來對G e t L a s t E r r o r的呼叫將返回E R R O R _ C A L L _ N O T _ I M P L E M E N T E D

    另一種情況也會導致系統動態地提高執行緒的優先順序等級。比如有一個優先順序為 4的執行緒準備執行但是卻不能執行,因為一個優先順序為8的執行緒正連續被排程。在這種情況下,優先順序為4的執行緒就非常渴望得到C P U時間。當系統發現一個執行緒在大約34 s內一直渴望得到C P U時間,它就將這個渴望得到C P U時間的執行緒的優先順序動態提高到1 5,並讓該執行緒執行兩倍於它的時間量。當到了兩倍時間量的時候,該執行緒的優先順序立即返回到它的基本優先順序。

7.9.2 為前臺程序調整排程程式

   當用戶對程序的視窗進行操作時,該程序就稱為前臺程序,所有其他程序則稱為後臺程序。當然,使用者希望他正在使用的程序比後臺程序具有更強的響應性。為了提高前臺程序的響應性,Wi n d o w s能夠為前臺程序中的執行緒調整其排程演算法。對於Windows 2000來說,系統可以為前臺程序的執行緒提供比通常多的C P U時間量。這種調整隻能在前臺程序屬於正常優先順序類的程序時才能進行。如果它屬於其他任何優先順序類,就無法進行任何調整。

    Windows 2000實際上允許使用者對這種調整進行相應的配置。在 System Properties(系統屬性)對話方塊的A d v a n c e d選項卡上,使用者可以單擊Performance Options(效能選項)按鈕,開啟圖7 - 3所示的對話方塊

 

    如果使用者選擇優化應用程式的效能,系統就執行配置的調整。如果使用者選擇優化後臺服務程式的效能,系統就不進行調整。當安裝 Windows 2000的專業版時,A p p l i c a t i o n s就會被預設選定。對於Windows 2000的所有其他版本,則預設選定Background Services,因為計算機將主要由非互動式使用者使用。

    當程序移到前臺時,Windows 98也會對正常優先順序類的程序中的執行緒排程演算法進行調整。當一個優先順序為正常的程序移到前臺時,系統便將最低、低於正常、正常、高於正常和最高等優先順序的執行緒的優先順序提高 1,優先順序為空閒和關鍵時間的執行緒的優先順序則不予提高。因此,在正