一.為什么需要優先級--線程調度的問題
在現實生活中,優先級是一個很常見的現象:在火車站,如果你是孕婦,你是可以走進站中的專門綠色通道的,可以提前上火車以免擁擠;火警119匪警110出警的時候,都是人命關天的大事,是可以優先使用道路的,行人和車輛一律避讓;在銀行,如果你是白金VIP,也會有專門的綠色通道供你使用.從社會公平層面的優先級,到商業活動中的優先級,大家每天都生活在這樣的環境之中,而且是按照這套游戲規則行事。
Windows是一個用戶操作系統,在設計上遵循着穩定性為准則,也就是說他要與人類的思維方式保持一致,才能用得舒服,線程的優先級可以說就是這一原則下的產物.如果都讓車輛在路上一直依次行駛,那么120到現場的時候,人都可能已經掛了;如果病毒一直搶占CPU,那殺毒軟件也就沒有什么卵用了。
這里需要注意現實生活中優先級與Windows中優先級的不同之處,現實生活中,我們可以通過新增資源(如增加窗口)優先處理高級別的業務,也可以通過對共同資源的調度(如110出警)來處理優化優先級高的業務。Windows則是在借鑒這些思路的時候進行了自己的一些改造,如調度隊列、動態優先級調整等。
二.了解Windows的線程調度
Windows進化到現在,已經是一個時分和搶占式操作系統,它不同於實時操作系統,它通過動態地調整線程等待隊列,從而確定線程使用cpu時間片的順序。優先級高的線程有更大的概率排在隊列的前面,同時獲得更多數量的時間片,而不是更長時間的時間片。
線程如果被sleep掉、等待io時,會釋放他所擁有的cpu,如果線程不是主動釋放CPU,線程調度器會搶占該線程。如果優先級相同的多個線程等待使用CPU,則會使用一個循環調度規則來實現隊列的先后順序。
前面我們說過優先級是動態調整的,優先級低的不可能一直都是在等待,隨着時間的運轉,低優先級線程的優先級會提升,這樣線程才有可能在等待結束時獲得CPU。
再次強調,線程優先級只是提高了線程被調用的概率,並不是定義CPU調用線程的順序,具體的工作就交給操作系統內部了。
三.C#中的線程優先級
C#中為我們提供了5個線程優先級別,如下所示:
線程默認的優先級為Normal,可以在線程的運行過程中修改線程的優先級,如下所示:
1 static void Main(string[] args) 2 { 3 Thread th = new Thread(delegate() { Console.WriteLine("start a new thread"); }); 4 Console.WriteLine(th.Priority); 5 th.Start(); 6 th.Priority = ThreadPriority.Lowest; 7 Console.WriteLine(th.Priority); 8 Console.Read(); 9 }
結果如下:
四.優先級反轉
這里要用到鎖的知識,對這塊有疑問的可以先去大致了解下鎖。
假設一種情況,線程A是高優先級線程,線程B是低優先級線程,線程B等啊等,終於等到自己,然后它鎖住了一個資源R,然后線程A接手,但是它要用到R,R被鎖,然后A只有等待B釋放鎖,然而B優先級低,它只有經過漫長的等待才能提高自己的優先級得到執行,而此時A仍然在等待B釋放鎖,從表而看線程A是有非常多的執行機會,但線程A並未執行任何代碼,反而B一直在執行,那么線程A何時能夠得到資源呢?不知道,原來的優先級設定也就失去了意義。這就是所謂的優先級反轉。
那么,如何避免這一問題呢?這里給出一些建議。
1.鎖的尺寸應該盡量小,就是使用小鎖而非大鎖,比如鎖定字符串就是一個非常大的鎖
2.鎖的代碼應該盡量短,這樣鎖定的時間就會盡量少
3.可以使用原子鎖
使用優先級繼承:也就是,高優先級進程TH在等待低優先級的線程TL占用的競爭資源時,為了使TH能夠盡快獲得調度運行,由操作系統把TL的優先級提高到TH的優先級,從而讓TL以TH的優先級參與調度,盡快讓TL執行並釋放掉TH欲獲得的競爭資源,然后TL的優先級調整到繼承前的水平,此時TH可獲得競爭資源而繼承執行。優先級繼承還可以存在傳遞性,也就是說TL還需要更低的低優先級線程TM的同步資源時,也會把TM的線程優先級拉高到TL,這要看各個操作系統的具體實現。
五.結尾
在做應用程序時,我們建議,盡量不去干預線程的優先級,把調度的順序交給操作系統處理就好。
六.參考
《C#高級編程(第7版)》
博客 http://blog.csdn.net/feixiaoxing/article/details/7061582
博客 http://blog.csdn.net/thl789/article/details/617629