libevent原始碼深度剖析十一

2021-05-17 19:26:18 字數 1515 閱讀 9848

——時間管理

張亮為了支援定時器,libevent必須和系統時間打交道,這一部分的內容也比較簡單,主要涉及到時間的加減輔助函式、時間快取、時間校正和定時器堆的時間值調整等。下面就結合源**來分析一下。

libevent在初始化時會檢測系統時間的型別,通過呼叫函式detect_monotonic()完成,它通過呼叫clock_gettime()來檢測系統是否支援monotonic時鐘型別:

monotonic時間指示的是系統從boot後到現在所經過的時間,如果系統支援monotonic時間就將全域性變數use_monotonic設定為1,設定use_monotonic到底有什麼用,這個在後面說到時間校正時就能看出來了。

結構體event_base中的tv_cache,用來記錄時間快取。這個還要從函式gettime()說起,先來看看該函式的**:

如果tv_cache已經設定,那麼就直接使用快取的時間;否則需要再次執行系統呼叫獲取系統時間。

函式evutil_gettimeofday()用來獲取當前系統時間,在linux下其實就是系統呼叫gettimeofday();windows沒有提供函式gettimeofday,而是通過呼叫_ftime()來完成的。

在每次系統事件迴圈中,時間快取tv_cache將會被相應的清空和設定,再次來看看下面event_base_loop的主要**邏輯:

時間event_tv指示了dispatch()上次返回,也就是i/o事件就緒時的時間,第一次進入迴圈時,由於tv_cache被清空,因此gettime()執行系統呼叫獲取當前系統時間;而後將會更新為tv_cache指示的時間。

時間tv_cache在dispatch()返回後被設定為當前系統時間,因此它快取了本次i/o事件就緒時的時間(event_tv)。

從**邏輯裡可以看出event_tv取得的是tv_cache上一次的值,因此event_tv應該小於tv_cache的值。

設定時間快取的優點是不必每次獲取時間都執行系統呼叫,這是個相對費時的操作;在上面標註的時間點2到時間點1的這段時間(處理就緒事件時),呼叫gettime()取得的都是tv_cache快取的時間。

如果系統支援monotonic時間,該時間是系統從boot後到現在所經過的時間,因此不需要執行校正。

根據前面的**邏輯,如果系統不支援monotonic時間,使用者可能會手動的調整時間,如果時間被向前調整了(ms前面第7部分講成了向後調整,要改正),比如從5點調整到了3點,那麼在時間點2取得的值可能會小於上次的時間,這就需要調整了,下面來看看校正的具體**,由函式timeout_correct()完成:

在調整小根堆時,因為所有定時事件的時間值都會被減去相同的值,因此雖然堆中元素的時間鍵值改變了,但是相對關係並沒有改變,不會改變堆的整體結構。因此只需要遍歷堆中的所有元素,將每個元素的時間鍵值減去相同的值即可完成調整,不需要重新調整堆的結構。

當然調整完後,要將event_tv值重新設定為tv_cache值了。

主要分析了一下libevent對系統時間的處理,時間快取、時間校正和定時堆的時間值調整等,邏輯還是很簡單的,時間的加減、設定等輔助函式則非常簡單,主要在標頭檔案evutil.h中,就不再多說了。

libevent原始碼深度剖析

序幕 張亮上來當然要先誇獎啦,libevent 有幾個顯著的亮點 事件驅動 event driven 高效能 輕量級,專注於網路,不如ace那麼臃腫龐大 源 相當精煉 易讀 跨平台,支援windows linux bsd和mac os 支援多種i o多路復用技術,epoll poll dev pol...

libevent原始碼深度剖析

上來當然要先誇獎啦,libevent 有幾個顯著的亮點 事件驅動 event driven 高效能 輕量級,專注於網路,不如ace那麼臃腫龐大 源 相當精煉 易讀 跨平台,支援windows linux bsd和mac os 支援多種i o多路復用技術,epoll poll dev poll sel...

libevent原始碼深度剖析

序幕 張亮上來當然要先誇獎啦,libevent 有幾個顯著的亮點 事件驅動 event driven 高效能 輕量級,專注於網路,不如ace那麼臃腫龐大 源 相當精煉 易讀 跨平台,支援windows linux bsd和mac os 支援多種i o多路復用技術,epoll poll dev pol...