【Libevent】Libevent学习笔记(三):事件循环
00. 目錄
文章目錄
- 00. 目錄
- 01. event_base_loop函數
- 02. event_base_dispatch函數
- 03. event_base_loopexit函數
- 04. event_base_loopbreak函數
- 05. event_base_got_exit函數
- 06. event_base_got_break函數
- 07. event_base_dump_events函數
- 08. event_base_dump_events函數
- 09. 廢棄的事件循環函數
- 10.參考
01. event_base_loop函數
一旦有了一個已經注冊了某些事件的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 morepending or active events, or until something calls event_base_loopbreak() orevent_base_loopexit(). You can override this behavior with the 'flags'argument.@param eb the event_base structure returned by event_base_new() orevent_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 becauseno 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 flagsThese 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直到其中沒有已經注冊的事件為止。執行循環的時候,函數重復地檢查是否有任何已經注冊的事件被觸發(比如說,讀事件的文件描述符已經就緒,可以讀取了;或者超時事件的超時時間即將到達)。如果有事件被觸發,函數標記被觸發的事件為“激活的”,并且執行這些事件。
在flags參數中設置一個或者多個標志就可以改變event_base_loop()的行為。如果設置了EVLOOP_ONCE,循環將等待某些事件成為激活的,執行激活的事件直到沒有更多的事件可以執行,然會返回。如果設置了EVLOOP_NONBLOCK,循環不會等待事件被觸發:循環將僅僅檢測是否有事件已經就緒,可以立即觸發,如果有,則執行事件的回調。
完成工作后,如果正常退出,event_base_loop()返回0;如果因為后端中的某些未處理錯誤而退出,則返回-1。
為幫助大家理解,這里給出event_base_loop()的算法概要:
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.elseWait 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; }02. event_base_dispatch函數
event_base_dispatch()等同于沒有設置標志的event_base_loop()。所以,event_base_dispatch()將一直運行,直到沒有已經注冊的事件了,或者調用了event_base_loopbreak()或者event_base_loopexit()為止。
/**Event dispatching loopThis loop will run the event base until either there are no more pending oractive, or until something calls event_base_loopbreak() orevent_base_loopexit().@param base the event_base structure returned by event_base_new() orevent_base_new_with_config()@return 0 if successful, -1 if an error occurred, or 1 if we exited becauseno 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*版就存在了。
03. event_base_loopexit函數
/**Exit the event loop after the specified timeThe next event_base_loop() iteration after the given timer expires willcomplete normally (handling all queued events) then exit withoutblocking 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當前正在執行任何激活事件的回調,則回調會繼續運行,直到運行完所有激活事件的回調之才退出。
04. event_base_loopbreak函數
/**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 toread from a watchdog socket. When that happens, we'll call thecb function, which will make the loop exit immediately withoutrunning 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-secondtimer, 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; }05. event_base_got_exit函數
有時候需要知道對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 afterevent_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而退出 返回trueif (event_base_got_exit(base)){printf("event_base_got_exit return true\n");}} event_base_free(base);return 0; }06. event_base_got_break函數
有時候需要知道對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 afterevent_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 其它情況07. event_base_dump_events函數
有時候需要在事件回調中獲取當前時間的近似視圖,但不想調用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 callinggettimeofday() or clock_gettime() as appropriate if there is nocached time.Generally, this value will only be cached while actuallyprocessing event callbacks, and may be very inaccuate if yourcallbacks 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新引入的。
08. event_base_dump_events函數
為幫助調試程序(或者調試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版本中引入。
09. 廢棄的事件循環函數
前面已經討論過,老版本的libevent 具有“當前”event_base的概念。
本文討論的某些事件循環函數具有操作當前event_base的變體。除了沒有base參數外,這些函數跟當前新版本函數的行為相同。
2.0版本之前的event_base是不支持鎖的,所以這些函數并不是完全線程安全的:不允許在執行事件循環的線程之外的其他線程中調用*_loopbreak()或者_loopexit()*函數。
10.參考
相關書籍: http://www.wangafu.net/~nickm/libevent-book/Ref2_eventbase.html
官方參考網站: https://www.monkey.org/~provos/libevent/doxygen-2.0.1/index.html
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的【Libevent】Libevent学习笔记(三):事件循环的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Libevent】Libevent学习
- 下一篇: 【STM32】DMA详解