目錄html
聲明: 該博客來源於傳智播客C++學院相關培訓參考手冊算法
一旦有了一個已經註冊了某些事件的event_base(關於如何建立和註冊事件請看筆記四),就須要讓libevent等待事件而且通知事件的發生。後端
event_base_loop函數緩存
/** Wait for events to become active, and run their callbacks. This is a more flexible version of event_base_dispatch(). By default, this loop will run the event base until either there are no more pending or active events, or until something calls event_base_loopbreak() or event_base_loopexit(). You can override this behavior with the 'flags' argument. @param eb the event_base structure returned by event_base_new() or event_base_new_with_config() @param flags any combination of EVLOOP_ONCE | EVLOOP_NONBLOCK @return 0 if successful, -1 if an error occurred, or 1 if we exited because no events were pending or active. @see event_base_loopexit(), event_base_dispatch(), EVLOOP_ONCE, EVLOOP_NONBLOCK */ int event_base_loop(struct event_base *base, int flag); //while(1) { .... } 功能: 等待事件被觸發, 而後執行對應的回調函數 參數: base: event_base_new的返回值 flag: 標誌 返回值: 成功: 0成功 1表示沒有事件觸發 失敗: -1
循環相關標誌:安全
/** @name Loop flags These flags control the behavior of event_base_loop(). */ /**@{*/ /** Block until we have an active event, then exit once all active events * have had their callbacks run. */ #define EVLOOP_ONCE 0x01 /** Do not block: see which events are ready now, run the callbacks * of the highest-priority ones, then exit. */ #define EVLOOP_NONBLOCK 0x02 /**@}*/
默認狀況下,event_base_loop()函數運行event_base直到其中沒有已經註冊的事件爲止。執行循環的時候,函數重複地檢查是否有任何已經註冊的事件被觸發(好比說,讀事件的文件描述符已經就緒,能夠讀取了;或者超時事件的超時時間即將到達)。若是有事件被觸發,函數標記被觸發的事件爲「激活的」,而且執行這些事件。app
在flags參數中設置一個或者多個標誌就能夠改變event_base_loop()的行爲。若是設置了EVLOOP_ONCE,循環將等待某些事件成爲激活的,執行激活的事件直到沒有更多的事件能夠執行,然會返回。若是設置了EVLOOP_NONBLOCK,循環不會等待事件被觸發:循環將僅僅檢測是否有事件已經就緒,能夠當即觸發,若是有,則執行事件的回調。less
完成工做後,若是正常退出,event_base_loop()返回0;若是由於後端中的某些未處理錯誤而退出,則返回-1。socket
爲幫助你們理解,這裏給出event_base_loop()的算法概要:ide
while (any events are registered with the loop) { if (EVLOOP_NONBLOCK was set, or any events are already active) If any registered events have triggered, mark them active. else Wait until at least one event has triggered, and mark it active. for (p = 0; p < n_priorities; ++p { if (any event with priority of p is active) { Run all active events with priority of p. break; /* Do not run any events of a less important priority */ } } if (EVLOOP_ONCE was set or EVLOOP_NONBLOCK was set) break; }
event_base_dispatch()等同於沒有設置標誌的event_base_loop()。因此,event_base_dispatch()將一直運行,直到沒有已經註冊的事件了,或者調用了event_base_loopbreak()或者event_base_loopexit()爲止。函數
/** Event dispatching loop This loop will run the event base until either there are no more pending or active, or until something calls event_base_loopbreak() or event_base_loopexit(). @param base the event_base structure returned by event_base_new() or event_base_new_with_config() @return 0 if successful, -1 if an error occurred, or 1 if we exited because no events were pending or active. @see event_base_loop() */ int event_base_dispatch(struct event_base *base); 等價於沒有設置標誌的 event_base_loop函數
event_base_dispatch()將一直運行,直到沒有已經註冊的事件了,或者調用了event_base_loopbreak()或者event_base_loopexit()爲止。
這些函數定義在<event2/event.h>中,從libevent 1.0版就存在了。
/** Exit the event loop after the specified time The next event_base_loop() iteration after the given timer expires will complete normally (handling all queued events) then exit without blocking for events again. Subsequent invocations of event_base_loop() will proceed normally. @param eb the event_base structure returned by event_init() @param tv the amount of time after which the loop should terminate, or NULL to exit after running all currently active events. @return 0 if successful, or -1 if an error occurred @see event_base_loopbreak() */ int event_base_loopexit(struct event_base *base, const struct timeval *tv); 功能: 讓event_base在給定時間以後中止循環。 參數: base event_base_new的返回值 tv 表示延時的時間,若是爲NULL 當即中止循環,沒有延時 返回值: 成功: 0成功 失敗: -1
注意:
若是event_base當前正在執行任何激活事件的回調,則回調會繼續運行,直到運行完全部激活事件的回調之才退出。
/** Abort the active event_base_loop() immediately. event_base_loop() will abort the loop after the next event is completed; event_base_loopbreak() is typically invoked from this event's callback. This behavior is analogous to the "break;" statement. Subsequent invocations of event_loop() will proceed normally. @param eb the event_base structure returned by event_init() @return 0 if successful, or -1 if an error occurred @see event_base_loopexit() */ int event_base_loopbreak(struct event_base *base); 功能: 讓event_base當即中止循環。 參數: base event_base_new的返回值 返回值: 成功: 0成功 失敗: -1
這些函數聲明在<event2/event.h>中。event_break_loopexit()函數首次在libevent 1.0c版本中實現;event_break_loopbreak()首次在libevent 1.4.3版本中實現。
注意:
event_base_loopbreak()讓event_base當即退出循環。它與event_base_loopexit(base,NULL)的不一樣在於,若是event_base當前正在執行激活事件的回調,它將在執行完當前正在處理的事件後當即退出。
event_base_loopexit(base,NULL)和event_base_loopbreak(base)在事件循環沒有運行時的行爲不一樣:前者安排下一次事件循環在下一輪迴調完成後當即中止(就好像帶EVLOOP_ONCE標誌調用同樣);後者卻僅僅中止當前正在運行的循環,若是事件循環沒有運行,則沒有任何效果。
官方參考示例一: 當即退出循環
#include <event2/event.h> /* Here's a callback function that calls loopbreak */ void cb(int sock, short what, void *arg) { struct event_base *base = arg; event_base_loopbreak(base); } void main_loop(struct event_base *base, evutil_socket_t watchdog_fd) { struct event *watchdog_event; /* Construct a new event to trigger whenever there are any bytes to read from a watchdog socket. When that happens, we'll call the cb function, which will make the loop exit immediately without running any other active events at all. */ watchdog_event = event_new(base, watchdog_fd, EV_READ, cb, base); event_add(watchdog_event, NULL); event_base_dispatch(base); }
官方參考示例二: 執行事件循環10秒,而後退出
#include <event2/event.h> void run_base_with_ticks(struct event_base *base) { struct timeval ten_sec; ten_sec.tv_sec = 10; ten_sec.tv_usec = 0; /* Now we run the event_base for a series of 10-second intervals, printing "Tick" after each. For a much better way to implement a 10-second timer, see the section below about persistent timer events. */ while (1) { /* This schedules an exit ten seconds from now. */ event_base_loopexit(base, &ten_sec); event_base_dispatch(base); puts("Tick"); } }
測試代碼: 每隔3秒鐘輸出一個字符串
#include <stdio.h> #include <event.h> int main(void) { struct event_base *base = NULL; struct timeval tmo = {3, 0}; base = event_base_new(); if (NULL == base) { printf("event_base_new failded...\n"); return 1; } while(1) { //設置三秒鐘退出事件循環 event_base_loopexit(base, &tmo); //進入事件循環 event_base_dispatch(base); printf("hello itcast\n"); } event_base_free(base); return 0; }
有時候須要知道對event_base_dispatch()或者event_base_loop()的調用是正常退出的,仍是由於調用event_base_loopexit()或者event_base_break()而退出的。能夠調用下述函數來肯定是否調用了loopexit或者break函數。
/** Checks if the event loop was told to exit by event_loopexit(). This function will return true for an event_base at every point after event_loopexit() is called, until the event loop is next entered. @param eb the event_base structure returned by event_init() @return true if event_base_loopexit() was called on this event base, or 0 otherwise @see event_base_loopexit() @see event_base_got_break() */ int event_base_got_exit(struct event_base *base); 功能: 判斷循環是否由於調用event_base_loopexit()或者event_base_break()而退出的時候返回true,不然返回false。下次啓動事件循環的時候,這些值會被重設。 參數: base event_base_new的返回值 返回值: true 循環是由於調用對應的函數而退出 0 其它狀況
參考示例:
#include <stdio.h> #include <event.h> int main(void) { struct event_base *base = NULL; struct timeval tmo = {3, 0}; base = event_base_new(); if (NULL == base) { printf("event_base_new failded...\n"); return 1; } while(1) { event_base_loopexit(base, &tmo); event_base_dispatch(base); printf("hello itcast\n"); //若是事件循環由於event_base_loopexit而退出 返回true if (event_base_got_exit(base)) { printf("event_base_got_exit return true\n"); } } event_base_free(base); return 0; }
有時候須要知道對event_base_dispatch()或者event_base_loop()的調用是正常退出的,仍是由於調用event_base_loopexit()或者event_base_break()而退出的。能夠調用下述函數來肯定是否調用了loopexit或者break函數。
/** Checks if the event loop was told to abort immediately by event_loopbreak(). This function will return true for an event_base at every point after event_loopbreak() is called, until the event loop is next entered. @param eb the event_base structure returned by event_init() @return true if event_base_loopbreak() was called on this event base, or 0 otherwise @see event_base_loopbreak() @see event_base_got_exit() */ int event_base_got_break(struct event_base *base); 功能: 判斷循環是否由於調用event_base_loopexit()或者event_base_break()而退出的時候返回true,不然返回false。下次啓動事件循環的時候,這些值會被重設。 參數: base event_base_new的返回值 返回值: true 循環是由於調用對應的函數而退出 0 其它狀況
有時候須要在事件回調中獲取當前時間的近似視圖,但不想調用gettimeofday()(多是由於OS將gettimeofday()做爲系統調用實現,而你試圖避免系統調用的開銷)。
在回調中,能夠請求libevent開始本輪迴調時的當前時間視圖。
void event_base_dump_events(struct event_base *, FILE *); /** Sets 'tv' to the current time (as returned by gettimeofday()), looking at the cached value in 'base' if possible, and calling gettimeofday() or clock_gettime() as appropriate if there is no cached time. Generally, this value will only be cached while actually processing event callbacks, and may be very inaccuate if your callbacks take a long time to execute. Returns 0 on success, negative on failure. */ int event_base_gettimeofday_cached(struct event_base *base, struct timeval *tv); 若是event_base當前正在執行回調,event_base_gettimeofday_cached()函數設置tv_out參數的值爲緩存的時間。不然,函數調用evutil_gettimeofday()獲取真正的當前時間。成功時函數返回0,失敗時返回負數。 返回值: 成功 0 失敗 負數
注意:
注意,由於libevent在開始執行回調的時候時間值會被緩存,因此這個值至少是有一點不精確。若是回調執行很長時間,這個值將很是不精確。
這個函數是libevent 2.0.4-alpha新引入的。
爲幫助調試程序(或者調試libevent),有時候可能須要已經加入到event_base的全部事件及其狀態的完整列表。調用event_base_dump_events()能夠將這個列表輸出到指定的文件中。
這個列表是人可讀的,將來版本的libevent將會改變其格式。
void event_base_dump_events(struct event_base *base, FILE *file); 功能: 轉儲event_base的狀態到文件中。 參數: base event_base_new的返回值 file FILE類型指針 返回值: 無
這個函數在libevent 2.0.1-alpha版本中引入。
前面已經討論過,老版本的libevent 具備「當前」event_base的概念。
本文討論的某些事件循環函數具備操做當前event_base的變體。除了沒有base參數外,這些函數跟當前新版本函數的行爲相同。
2.0版本以前的event_base是不支持鎖的,因此這些函數並非徹底線程安全的:不容許在執行事件循環的線程以外的其餘線程中調用*_loopbreak()或者_loopexit()*函數。
相關書籍: http://www.wangafu.net/~nickm/libevent-book/Ref2_eventbase.html
官方參考網站: https://www.monkey.org/~provos/libevent/doxygen-2.0.1/index.html