1. 程式人生 > >三 基本使用場景和事件流程

三 基本使用場景和事件流程

1  前言
學習原始碼該從哪裡入手?我覺得從程式的基本使用場景和程式碼的整體處理流程入手
是個不錯的方法,至少從個人的經驗上講,用此方法分析 libevent 是比較有效的。
2  基本應用場景
基本應用場景也是使用 libevnet 的基本流程,下面來考慮一個最簡單的場景,使用
livevent 設定定時器,應用程式只需要執行下面幾個簡單的步驟即可。
1)首先初始化 libevent 庫,並儲存返回的指標
struct event_base * base = event_init();
實際上這一步相當於初始化一個 Reactor 例項;在初始化 libevent 後,就可以註冊事件了。
2)初始化事件 event,設定回撥函式和關注的事件
evtimer_set(&ev, timer_cb, NULL);
事實上這等價於呼叫 event_set(&ev, -1, 0, timer_cb, NULL);

event_set 的函式原型是:

void event_set(struct event *ev, int fd, short event, void (*cb)(int,
short, void *), void *arg)
ev:執行要初始化的 event 物件;
fd:該 event 繫結的“控制代碼”,對於訊號事件,它就是關注的訊號;
event:在該 fd 上關注的事件型別,它可以是 EV_READ, EV_WRITE, EV_SIGNAL;
cb:這是一個函式指標,當 fd 上的事件 event 發生時,呼叫該函式執行處理,它有三個引數,
呼叫時由 event_base 負責傳入,按順序,實際上就是 event_set 時的 fd, event 和 arg;
arg:傳遞給 cb 函式指標的引數;
由於定時事件不需要 fd,並且定時事件是根據新增時(event_add)的超時值設定的,因此
這裡 event 也不需要設定。
這一步相當於初始化一個 event handler,在 libevent 中事件型別儲存在 event 結構體中。
注意:libevent 並不會管理 event 事件集合,這需要應用程式自行管理;
3)設定 event 從屬的 event_base
event_base_set(base, &ev);
這一步相當於指明 event 要註冊到哪個 event_base 例項上;
4)是正式的新增事件的時候了
event_add(&ev, timeout);

基本資訊都已設定完成,只要簡單的呼叫 event_add()函式即可完成,其中 timeout 是定時值;

這一步相當於呼叫 Reactor::register_handler()函式註冊事件。

5)程式進入無限迴圈,等待就緒事件並執行事件處理

event_base_dispatch(base);

3  例項程式碼
上面例子的程式程式碼如下所示


struct event ev;
struct timeval tv;
void time_cb(int fd, short event, void *argc)
{
printf("timer wakeup\n");
event_add(&ev, &tv); // reschedule timer
}
int main()
{
struct event_base *base = event_init();
tv.tv_sec = 10; // 10s period
tv.tv_usec = 0;
evtimer_set(&ev, time_cb, NULL);
event_add(&ev, &tv);
event_base_dispatch(base);
}
4  事件處理流程
當應用程式向 libevent 註冊一個事件後,libevent 內部是怎麼樣進行處理的呢?下面的
圖就給出了這一基本流程。
1) 首先應用程式準備並初始化 event,設定好事件型別和回撥函式;這對應於前面第步驟
2 和 3;
2) 向 libevent 新增該事件 event。對於定時事件,libevent 使用一個小根堆管理,key 為超
時時間;對於 Signal 和 I/O 事件,libevent 將其放入到等待連結串列(wait list)中,這是一
個雙向連結串列結構;
3) 程式呼叫 event_base_dispatch()系列函式進入無限迴圈,等待事件,以 select()函式為例;
每次迴圈前 libevent 會檢查定時事件的最小超時時間 tv,根據 tv 設定 select()的最大等
待時間,以便於後面及時處理超時事件;
當 select()返回後,首先檢查超時事件,然後檢查 I/O 事件;
11
Libevent 將所有的就緒事件,放入到啟用連結串列中;

然後對啟用連結串列中的事件,呼叫事件的回撥函式執行事件處理;


5  小結
本節介紹了 libevent 的簡單實用場景,並旋風般的介紹了 libevent 的事件處理流程,讀
者應該對 libevent 有了基本的印象,下面將會詳細介紹 libevent 的事件管理框架(Reactor 模
式中的 Reactor 框架)做詳細的介紹,在此之前會對原始碼檔案做簡單的分類。