C++線程安全的高精度定時器(時間堆)實現

time_heap(時間堆)

  • 適合事件驅動系統的時間堆定時器,所有接口都儘量設計的簡單易用。
  • 現在大部分流行的定時器一般分爲兩種,時間輪,時間堆。基於設計上而言。時間輪可以設計爲滴答檢測超時事件,或者直接在循環中檢查超時事件。而時間堆異同。
  • 我之前就寫過一個基於滴答檢測超時事件的定時器,這樣的機制會造成一個問題。那就是由於休眠喚醒的時間總會有微小的誤差(每次滴答),那麼每次的誤差積累起來就會越來越大。導致定時時長過長的事件的時間誤差越大。所以只能在某些不需要太過精準定時時長的地方使用。
  • 接下來我們來看看在循環裏檢測超時事件的定時器吧,這種類型的定時器只有一個問題。那就是佔用不必要的性能消耗。如果是在事件驅動系統那麼將造成很大的性能浪費。
  • 那我們的時間堆呢。它有問題嗎?當然有。那就是如果連續插入大量定時時長過短的定時事件那麼就會造成事件觸發事件延遲,延遲的時間根據事件的數量和觸發時間而定。其實循環檢測超時事件的定時器和時間輪也會有這個問題,但是他們的觸發事件延遲比時間堆短的多。我在自己電腦上測試插入10w個50ms後執行的定時器。其最後一個定時器執行的時間比循環檢測超時事件的定時器多了300ms左右。
  • 接下來說說我爲什麼選擇時間堆作爲項目使用中的定時器:
  1. 不浪費性能,使用WaitForSingleObject函數直接休眠到下一個事件觸發時間再喚醒執行任務;
  2. 相比起另外兩個機制的定時器,其短時間執行大量定時事件的延遲還能接受;
  3. 對於定時時長較長的事件基本0延遲,我的電腦在10w個2s後定時事件下0延遲,具體情況還是要根據電腦配置,事件數量,事件觸發時間決定(當然我的電腦比較垃圾,嘿嘿);
  4. 以上的測試都是在Debug_x64下測試的。Release環境下300ms的延遲在100左右

上面已經說了優缺點,接下來說下可以優化的點:
5. 在時間堆中使用內存池。
6. 加入異步執行任務。

代碼庫在github–> 點擊此處進入

使用代碼:

auto& timer = time_heap::instance();
double second = 5;	//定時時長(單位:秒,由於是double可以傳入0.05這樣的數字,會自動轉爲毫秒)
uint32_t count = 5;	//執行次數
//timer.add函數的返回值是一個std::shared_ptr對象。不用手動銷燬
auto timer1 = timer.add(second, count, [&](int index) {
	printf("%d\n");
	return index;
	}
, 1);	//不定參,可以使用任意類型個數的參數
//獲取事件函數返回值(若未事件未執行完成將堵塞)
auto result = timer1->get();
//安全的獲取事件函數返回值(若未事件未執行完成將堵塞,超過count次get完成後再次get將cash)
if (timer1->vaild) {
	auto result = timer1->get();
}
timer1->del();		        //刪除定時事件
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章