關於「Sleep 1 」呼叫的問題

2021-07-11 10:22:47 字數 2443 閱讀 7837

因為在專案中有很多定時的任務,而這些任務一般又是比較費時的任務,所以不方便在主線程中用視窗定時器來實現,因為這樣有可能會阻塞介面,從而導致介面卡頓。另外,用視窗定時器也導致邏輯**與介面**耦合。所以實現了乙個簡單的定時任務幫浦,其實現原理是這樣的。

首先,封裝了乙個任務基類,其中有乙個do虛方法。各種實際任務從這個類派生特定的任務子類,並實現do方法。

...

int count =0;

dowhile

(count < milliseconds);.

..

這樣實現後,在我的機器上測試了並且一切都感覺perfect,於是就分發了。

過了一陣子後,便有反饋,說一些定時任務並沒有執行。得到這個反饋,我是很憤慨的,內心立馬就嘀咕著:「我靠,不是在找茬吧,我當初可是測試了的,執行得很perfect呀。」

於是我又在自己機器上把條件設定成那樣執行了一遍,一切還是那樣perfect。我就有點生氣了,不過我沒有爆發,謹慎的把目標機器的執行日誌拿了過來,發現確實沒有定時任務執行的日誌記錄。這下子,我感覺有點不妙了,這應該是事實。那台機確實沒有perfect的執行。

於是,憑直覺的,我感覺問題應該出在了sleep(1)上,於是在網上搜尋了這個呼叫,綜合了一下,大致把問題是搞明白了。

其實,這個問題的深度,要深可以深,要淺也可以淺。因為這個問題如果追根究底是可以找到作業系統核心的。

我當初在網上搜尋是搜尋到了,說sleep的精度因系統平台而異,一般是16毫秒左右,不過也可以到1毫秒。也就是說,如果精度是16毫秒,而sleep(1)這樣的呼叫是不行的,因為每一次這樣的呼叫誤差是16倍,如果乙個任務定時是1個小時,那實際就是16個小時,而說不定沒到16個小時軟體就可能被重啟了,所以定時任務會得不到執行。而如果精度是1毫秒,那麼就會執行得比較perfect,就如同我的機器上那樣。如果從淺裡講,原因到這兒也就over了。

但是如果還不滿意這樣的解釋,也是可以更進一步的。這就涉及到作業系統核心的知識了。其實作業系統對於所有的定時的實現是依賴於硬體時鐘的,執行緒的切換也是跟這相關的。這個所謂的硬體時鐘實現了乙個時間中斷,每隔一定的時間會去打斷cpu一下,讓cpu中斷現在執行的東西而去執行與定時相關的東西,比如檢查某個定時是不是到期了該觸發了。sleep本質上也用到了定時,所以也與這個硬體時鐘有關。而上面所說的精度便是指這個硬體時鐘發出這樣的時間中斷的間隔時間。

因為到期的檢查是以一定的間隔來檢查的。如果定時的時間小於這個檢查時間間隔,於是便有誤差產生了。比如,1毫秒的定時時間,16毫秒檢查一次有沒有到期。如果這個定時呼叫sleep(1)離即將到來的最近的一次檢查的時間距離小於1毫秒,則這次不會檢查到到期,到下一次才會檢查到,從而就產生了乙個16+毫秒的實際定時。如果這個定時呼叫sleep(1)離即將到來的最近的一次檢查的時間距離大於等於1毫秒,可能就在最近的一次檢查就到期了,從而就產生乙個16-毫秒的實際定時,比上一種情況好那麼一點,但是也是有誤差的。

當然,如果這個硬體時鐘的中斷時間是1毫秒,也就是定時是1毫秒檢查一次,那麼,基本上就不會出現上面的情況,也就基本沒有誤差了。這便是這個問題的深層次的解釋。

知道了原因是不夠的,還要有解決方案,這個問題的根源其實就是這個硬體時鐘的中斷時間太大,如果調小一點不就ok了。好在,windows作業系統上確實是可以調這個中斷時間的。這個系統呼叫便是timebeginperiod,當然還有乙個與之對應的timeendperiod系統呼叫。timebeginperiod用來請求系統設定乙個時間間隔,最小可以是1毫秒,而timeendperiod用來取消請求的設定。需要注意的是,這個設定是作業系統全域性的,所有的程序以及驅動程式共享的,系統會以最高的精度為準,因為只要滿足了最高精度,便滿足了所有的精度要求。如果程序沒有呼叫timeendperiod,作業系統會在這個程序退出時取消之前請求的設定。當最高精度的設定請求全部被取消時,作業系統會用次高精度的設定來重新設定。如果所有精度請求都取消了,系統會把這個時鐘間隔恢復到16毫秒左右。

當然,這個任務幫浦的實現其實可以不用sleep來實現的,用waitforsingleobject+setevent會更好,這個呼叫在等待的同時還會檢測乙個事件是否觸發,這個事件就是通知執行緒退出的事件,這樣就可以繞過對於sleep(1)的需要了。

如果一定要用sleep(1)的話,可以如下這樣用來避免對於sleep精度的依賴:

...

dword tick_count =::

gettickcount()

;while

(true)

else

}else

else}}

...

深入分析Sleep 0 與Sleep 1 的區別

深入分析sleep 0 與sleep 1 的區別 羅朝輝 目的 有時候我們想讓執行緒不被排程一定的時間,也就是說讓執行緒睡眠一段時間。api 介面 在 win32中可以呼叫 sleep,sleepex 和 switchtothread 三個api。void winapi sleep dword dw...

深入分析Sleep 0 與Sleep 1 的區別

深入分析sleep 0 與sleep 1 的區別 羅朝輝 目的 有時候我們想讓執行緒不被排程一定的時間,也就是說讓執行緒睡眠一段時間。api 介面 在 win32中可以呼叫 sleep,sleepex 和 switchtothread 三個api。void winapi sleep dword dw...

關於sleep的理解

unix是按時間片輪轉排程,windows是搶占式排程 以吃蛋糕為例子,10個人吃蛋糕,如果是unix下,假設開始時,每個人都處於就緒狀態,那麼作業系統排程大家排好隊,按順序吃,每個人吃1分鐘,1分鐘就是作業系統給大家分配的時間片,那麼 1 有些人飯量大,吃乙份鐘也不飽,還想吃,但是作業系統在到1分...