Windows本身就是一個搶占式操作系統,它的實現,必定有某種算法在里面,比如什么時候調度哪些線程,需要花費多長時間等問題。
我們時時在用Windows,作為程序員,我們有必要知道其中最貼近我們的算法。
為什么這么說?我們對系統發出的命令,獲取信息等操作,Windows為什么能這么快作出反應嗎?這僅僅是上下文切換那30毫秒的功勞嗎?操作系統能依照人的操作,處理當前用戶最迫切的請求,並在最短時間內給出反應,這些原因我們應該知道。
有人會提,這是線程的功勞,對。這是線程的功勞,你在操作的時候,都是線程在處理你的請求,現在來了解下線程的屬性吧?
打開開始菜單,win7直接在搜索框中輸入spy,然后會彈出一個叫spy++的程序,運行spy++。這個東西是VS2010完整版才有。
這是個有趣的東西,好奇的同學可以試試看。現在來看看這個東西能做什么吧。
我找到了一個QQ的線程的窗口,然后右鍵,彈出菜單,然后選擇->消息。
出來一個框,數據一直再刷,然后再呼出QQ界面看?鼠標在QQ上面晃兩下,細心的你會發現。刷屏的消息是不是很有感覺?再心細的又會觀察一下屬性選項,進程ID你也會看到,一個應用程序也就一個進程,關系QQ的線程,所有的進程ID都會是一樣。在你每次操作的時候,Windows做着超乎你想象的工作,試一試,也許也會讓你驚呼。消息看完了,來監視下線程吧?在spy++中選擇 監視->線程
我找到的是QQ的線程:
上下文開關就是記錄Windows上下文切換次數,”2453261“這是系統已經調用QQ線程的次數。而你看到的,就是一個線程的屬性。
現在你也許又會有疑問了,為什么會這樣?
在前兩篇同系列文章中,提到過每個線程都有自己的屬性,在每個線程的內核對象之中,都包含一個上下文結構,上下文結構的存在是為了反映在線程上一次執行時,線程CUP寄存器的狀態。在任何時刻,Windows只將一個線程代碼分配給一個CPU,一個線程只允許運行一個時間片,在線程的“時間片”結束之后,Windows會檢查現有所有線程內核對象,只有那些沒有在等待什么的線程才時候調度。Windows選擇一個可調度的線程內核對象,並且換到它。
Windows選擇一個可調度的線程有一套獨特的標准,看到上圖中的線程的優先級了嗎?當前優先級和基本優先級,它是隨着程序的啟用與否波動的。
一個線程允許運行一個時間片,沒錯。但是,Windows執行線程的規律和時間片沒多大的關系,線程在運行的任何時刻都可以停止,然后Windows又去調度另一個線程,你有點控制權,去控制你想運行的線程,但是這控制權不多,不控制為好。
對於線程的執行,記住一點:
你不能保證自己的線程一直運行,你不能阻止其他的線程的運行。
因為Windows不是一個實時操作系統,想了解更多就請自行去深挖吧,我也不多寫了,免得扯出范圍(─.─|||。
現在把目光放到線程優先級上,每個想成為優秀的程序員,必須要了解的知識點。
線程優先級別0~31,Windows把線程用從高到低的調度方式輪流調度線程,假如有一個優先級別為31的線程運行結束了,然后Windows會找下一個空閑的線程,如果空閑的線程中有一個級別也是31的線程,那么Windows又會把31級別的線程交給CUP處理。
那就有人要問了,如果一直有31的線程級別,那豈不是低級別的線程Windows都不會去調用了?這不公平。
確實,Windows就是個這樣的不公平。有高級別線程,低級別線程沒有機會去請求使用CUP。
CPU正在運行一個低級別的線程,當一個優先級別高於正在運行的低級別的線程,級別高的線程請求調用CPU,那么,會怎么樣?
Windows會毫不猶豫的把正在運行的低級別線程趕走,然后放高級別的線程去使用CPU,就是有這么霸道。
較高優先級線程總是搶占較低級別線程,這有沒有弱肉強食的感覺?
好,說完級別調用的問題,就來看看,怎么設計應用程序的運行線程級別吧。
在設計應用程序時,應覺得自己的應用程序是需要比機器上同時運行的其他應用程序更大還是更小的響應能力,然后選擇一個進程優先級類(注意)。
為什么要引進進程優先級類?
Microsoft其實已經認識到,開發人員在為進程優先級分配時,很難做到完全合理,你不知道這個進程的優先級應該設為多少,為了解決這個分配優先級問題,Windows公開了優先級類的一個抽象層。以此來反應你的決定,Windows支持6個進程優先級類:Idel,Below Normal,Normal,Above Normal,Hight和Realtime(依次向高),其中Normal是默認的進程優先級,所以它是最常用的。
如果一個應用程序在系統什么都不做的情況下運行,就適合分配一個Idel的優先級類。估計QQ的離開狀態,屏保等是這么設計的,當然還有很多....
進程划級時,要考慮最關鍵的因素,不能讓進程妨礙其它更關鍵的任務,只有在絕對必要的時候才使用Hight優先級類,Realtime最高優先級一般得避免,因為它相當高,到31的級別了,它甚至可能干擾操作系統任務,比如阻礙一些網絡傳輸,磁盤讀寫等,你肯能覺得沒什么,除此之外,Realtime進程的線程可能造成不能及時的處理鍵盤和鼠標輸入,用戶覺得自己的計算機”崩了(死機)“,一定要有很好的理由才能使用Realtime優先級,比如響應一些延遲很短的硬件事件。
選好一個進程優先級類之后,你的程序和其他應用程序就不用再考慮了,現在把專注力放在應用程序的線程上:
Windows支持7個相對線程優先級:Idel,Lowest,Below Normal,Normal,Above Normal,Highest和Time-Critical。
這些是相對於進程優先級的,Normal依舊是默認的,它是最常用的,現在來打個比方,用個商場來做例子:
這圖勉強入眼。
每個服飾品牌都不一樣,代表着進程優先級不一樣。
每個品牌下的服飾的價格不一樣,代表着它們線程優先級不一樣。
比如阿迪達斯,耐克等,它們進程優先級高,里面相對應的線程優先級也高。因為它們價格比一般的品牌要貴。
品牌的高低決定服裝的價格,進程優先級的高低覺得相對線程優先級程度!經過這一舉例,下面這個表應該看得懂了:
相對線程優先級 | 進程優先級 | |||||
---|---|---|---|---|---|---|
Idle | Below Normal | Normal | Above Normal | High | Realtime | |
Time-critical | 15 | 15 | 15 | 15 | 15 | 31 |
Highest | 6 | 8 | 10 | 12 | 15 | 26 |
Above Normal | 5 | 7 | 9 | 11 | 14 | 25 |
Normal | 4 | 6 | 8 | 10 | 13 | 24 |
Below Normal | 3 | 5 | 7 | 9 | 12 | 23 |
Lowest | 2 | 4 | 6 | 8 | 11 | 22 |
Idle | 1 | 1 | 1 | 1 | 1 | 16 |
記住:
如果更改一個進程的優先級類,線程的相對優先級不會改變,但它的優先值會改變。
也許大家對這些表中數字會有疑惑,這代表的是先前說的0~31線程優先級別,但為什么這個表里面沒有“0”這個級別?
“0”這個級別是有的,不過它保留給零頁線程了,什么是零頁線程?系統在啟動時,會創建一個名為零頁線程的特殊線程,它是整個系統唯一線程級別為0的線程,它輔負責在沒有其他進程需要執行的時候,將系統的RAM所有空閑頁清零。表中還有一些數字沒有出現:17,18,19,20,21,27,28,29,30。這些線程級別不能被用戶模式獲得,在編寫運行於內核模式的設備驅動程序時,才可以獲得這些優先級。
還要注意的是,Realtime優先級的線程,其優先級不能低於16,類似的,非Realtime優先級的線程不能高於15。
進程優先級類和相對線程優先級有沒有分清楚呢?這個概念容易引起混淆,大家可能認為Windows能調度進程,然而,Windows永遠都不會調度進程,他調度的只有線程,“進程優先級類”是Microsoft提出的一個抽象概念,目的是為了幫助你理解自己的應用程序和其他正在運行的應用程序的關系,他沒有別的用途。
來看個設計實例:
現在有一個線程要設計,他用於長時間運行的計算限制任務,比如:編譯代碼,拼音檢查,電子表格計算等計算功能。一般是降低這線程的優先級,而不是提升線程的優先級。如果要設計一個快速的響應時間,然后運行非常短暫的時間,再回復等待狀態,則應提高該線程的優先級,這里總結的規律是,高優先級線程在其生命中的大多數時間里,都應處於等待狀態,這樣才不會影響熊的總體響應能力。
現在請按一下鍵盤右下角位置的Windows菜單鍵,看到效果了?Windows菜單立即搶占其他低級線程,並顯示它的菜單,用戶在菜單中上下移動時,菜單的線程會快速響應每一次按鍵或者鼠標移動。這是個很好的高優先級線程的例子,它在用戶關閉菜單后停止運行。
你可以更改它的線程相對優先級,Thread中的Priority屬性,向它傳遞ThreadPriority枚舉類型中定義的5各值之一,即在上表中的灰色部分列。
Windows為自己保留了優先級0和Realtime范圍,CLR為自己保留了Idle 和Time-Critical優先級。
CLR的終結器線程以Time-Critical優先級運行。開發人員不用用到這些優先級,但了解一下還是不錯的。
優先級的存在,使得應用程序需可以更人性化的處理用戶的請求,這設計的相當不錯,沒有它,我們不能隨意操控命令機器。
線程基礎只是講完了,作為開發人員應該知道,線程是非常寶貴的資源,必須省着用,為了做到這一點,最好的方式就是使用線程池ThreadPool。
這個下篇講,不得不說,線程池自動管理線程的創建和銷毀,這非常不錯。(^。^)y-~~