由於我們採用的伺服器一般都是靠鈕扣電池作為能源驅動和記錄時鐘,一般在執行一段時間後都會出現時間誤差。所以很多大規模的分布系統都有校時操作,特別是一些對時鐘要求精確的分布式系統(比如計費等),往往都會有乙個主機提供精確時鐘服務(其可能採用
gps校時),其他伺服器通過這台伺服器校時,校時操作一般都是直接改變系統時鐘。
ace的定時器都是採用
event_handler
進行處理,而
event_handler
一般而言都是採用絕對時間作為記錄超時的時間戳,但是絕對時間的方式在系統時鐘被調整的時候,會導致「丟失」部分定時器的處理,導致一些問題。
在設定定時器時,
schedule_timer
函式通過
gettimeofday
得到定時器時間點的時間。
template long
ace_select_reactor_t::schedule_timer
(ace_event_handler *handler,
const void *arg,
const ace_time_value &delay_time,
const ace_time_value &interval)
在派發定時器的過程中也是呼叫
gettimeofday
函式。
template ace_inline int
ace_timer_queue_t::expire (void)
可以看出,如果在
schedule_timer
後,將系統時鐘向前調節(調慢)以後,原有的定時器將要經過更多的時間才能觸發。從而導致這段時間內定時器無法觸發。從而造成定時器丟失。
這個問題的解決方法有
2個,簡單方法是將系統時鐘校準的頻度提高,保證每次校準的時候,系統的時鐘出現的偏差都不會影響時鐘的定時器觸發。
另外一種是
ace的
timer_queue
自己提供的方法,通過上面的**我們可以發現,其實
ace_timer_queue_t::gettimeofday
是乙個呼叫的是乙個函式指標。預設使用
ace_os:: gettimeofday
函式,這個函式可以替換的。
void gettimeofday (ace_time_value (*gettimeofday)(void));
ace提供乙個依賴於作業系統的高解析定時器,
ace_high_res_timer
,這個類是通過os的
tick
數量來得到更加精確的時鐘的【注】。
【注】os在啟動後,都會有乙個
tick
在不斷的計數,這個
tick
就像乙個打點計數器,每次增加
1.一般計數週期就是乙個
cpu週期。 由於
cpu的
tick
不會隨著你調整系統時鐘而調整。所以可以看做是乙個相對值。
ace_high_res_timer
可以根據相對值計算得到非常精確的程式執行時鐘,。直接使用
ace_high_res_timer:: gettimeofday_hr
函式作為
ace_timer_queue_t::gettimeofday
函式指標。並且在程式的開始部分使用函式,
ace_high_res_timer::global_scale_factor ()
,用於啟用高精度定時器。【注】
【注】這個方法得益於原來公司的兩位同事
zhangtianhu
和liaobincai
的乙個終結。在此懷念一下和他們共事的日子。另外,我沒有仔細研究過這個方法,由於獲取
cpu的
tick
的獲取很有可能是乙個核心操作,效率可能不高。
採用上述的兩個方法基本可以避免這個問題。
轉 STM32定時器時鐘 定時器的時鐘有倍頻功能
而外部的選8m經pll後,可以最大到72mhz systick由ahb固定8分頻後得到 apb2可以工作在72mhz下,而apb1最大是36mhz。sysclk 系統時鐘,最大72mhz hclk ahb匯流排時鐘,由系統時鐘sysclk 分頻得到,一般不分頻,等於系統時鐘 經過匯流排橋ahb ap...
ACE中的定時器實現原理
最近專案中遇到乙個問題,用ace框架起的定時器,跑著跑著,它不跑了,然後我依賴定時器所建立的任務也一直掛在那裡。檢視系統軟體列印的日誌發現,是ace的ace reactor在run reactor event loop函式中返回了 1,reactor的時間迴圈結束,從而導致定時器函式handle t...
定時器數碼管時鐘
mai.c handlebars include system.h include key.h extern uchar flag 1ms 在其他模組中尋找其定義。另外,extern也可用來進行鏈結指定。void main void 程式的主函式 在這裡插入 片key.c include key.h...