調度算法:Sleep并不總是如你預想的那樣起作用
作為上一篇文章”即使運行高優(yōu)先級線程,低優(yōu)先線程也能運行”的另一個反面例子,人們會認為調用 Sleep(0) 是一種放棄 CPU 時間片的簡單方法。舉個例子,如果消費者線程目前沒有數據可以處理,則可以調用此函數來出讓 CPU 時間片,以等待生產者線程產生需要的數據。
讓我們回想一下,調度程序會查找優(yōu)先級最高的可運行線程,如果存在平局,則所有候選項大致平均共享 CPU。線程可以調用 Sleep(0) 來放棄其時間片,從而減少其在 CPU 中的份額。但請注意,這并不能保證其他線程將運行。
如果存在具有最高優(yōu)先級的唯一可運行線程,它可以調用 Sleep(0),并保持很長一段時間,但它不會放棄 CPU。這是因為 Sleep 的時間為零會釋放分配給它的時間片,但使線程可運行。由于它是唯一具有最高優(yōu)先級的可運行線程,因此它會立即恢復 CPU。如果沒有其他人排隊,你實際上并沒有將時間片出讓給其他線程。
因此,如果使用 Sleep(0) 作為不那么有效的出讓 CPU 的方法,它永遠不會允許運行優(yōu)先級較低的線程。這意味著各種后臺活動(如索引)永遠不會有機會運行,因為你的程序占用了所有 CPU 時間。更重要的是,你的程序從未真正釋放 CPU 的事實,意味著計算機永遠不會進入低功耗狀態(tài)。筆記本電腦會更快地耗盡電池電量并運行得更熱,終端服務器將無休止地消耗 CPU 時間片。
最好的辦法是等待正確的同步對象,以便線程進入睡眠狀態(tài),直到有工作要做。如果你由于某種原因不能這樣做,至少 Sleep 一個非零的時間值。這樣,在短暫的時刻,你的線程不可運行,而其他線程(包括優(yōu)先級較低的線程) 有機會運行。(這也將在一定程度上降低功耗,盡管不如等待正確的同步對象那么多。)
總結
我們需要了解 CPU 時間片在各個線程上的調度原理,Sleep(0) 和 Sleep(1) 雖然只是參數上的不同,但底層運行邏輯卻有很大的區(qū)別。
由于程序可能會運行在各種不同配置的系統(tǒng)上,簡單的使用 Sleep 來進行線程同步,將產生預料不到的偏差,你絕對不希望這樣。
所以,正如原文作者指出的,多線程下的線程協(xié)調工作,還是使用內核同步對象比較好。
最后
Raymond Chen的《The Old New Thing》是我非常喜歡的博客之一,里面有很多關于Windows的小知識,對于廣大Windows平臺開發(fā)者來說,確實十分有幫助。
本文來自:《Consequences of the scheduling algorithm: Sleeping doesn’t always help》