libevent學習四
來源:程序員人生 發布時間:2015-02-06 08:30:42 閱讀次數:5294次
構建event_base
在你開始使用任何Libevent前,你需要先創建1個或多個event_base。每一個event_base管理著1個event的集合,并可以檢測出哪些event被激活了。如果event_base使用了鎖,就能夠在多線程中安全的訪問它。但要注意它的主poll函數只能被單個線程運行。如果你想用多個線程運行IO迭代器,你需要為每一個線程分配1個event_base。
注:在以后的版本中,Libevent可能提供對跨線程event的支持。
每一個event_base都有1個“方法”或主IO函數,用來肯定哪些event已被準備好。其中包括:
1. select
2. poll
3. epoll
4. kqueue
5. devpoll
6. evport
7. win32
使用者可以通過環境變量來禁用某個指定的主函數。如果你想去關掉kqueue函數,可以設置EVENT_NOKQUEUE這個環境變量等。如果你想在程序內部關掉,可以看下面對event_config_avoid_method的介紹:
設定默許的event_base
函數event_base_new()會創建1個默許設置的event_base。它根據相應的環境變量,返回1個指向event_base的指針。如果毛病返回NULL。
默許它會自動選擇系統所支持的最快的主函數。
接口
struct event_base *event_base_new(void);
對大多數程序,默許的設置就已滿足你的需求了。
定制自己的event_base
如果你想定制自己的event_base,你需要使用到event_config。event_config是個不對外開放的結構體。它保存著你對event_base偏好設定的相干信息。你可以通過傳入event_config到event_base_new_with_config()來創建event_base。
接口
struct event_config *event_config_new(void);
struct event_base *event_base_new_with_config(const struct event_config *cfg);
void event_config_free(struct event_config *cfg);
event_config_new()用來創建1個event_config。然后,調用其他的1些方法去告知它你想要的。最后通過event_base_new_with_config去創建1個event_base。創建后,通過event_config_free()來釋放event_config。
接口
int event_config_avoid_method(struct event_config *cfg, const char *method);
enum event_method_feature {
EV_FEATURE_ET = 0x01,
EV_FEATURE_O1 = 0x02,
EV_FEATURE_FDS = 0x04,
};
int event_config_require_features(struct event_config *cfg,
enum event_method_feature feature);
enum event_base_config_flag {
EVENT_BASE_FLAG_NOLOCK = 0x01,
EVENT_BASE_FLAG_IGNORE_ENV = 0x02,
EVENT_BASE_FLAG_STARTUP_IOCP = 0x04,
EVENT_BASE_FLAG_NO_CACHE_TIME = 0x08,
EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST = 0x10,
EVENT_BASE_FLAG_PRECISE_TIMER = 0x20
};
int event_config_set_flag(struct event_config *cfg,
enum event_base_config_flag flag);
event_config_avoid_method用來告知Libevent不要使用某個主函數。event_config_require_feature()用來告知Libevent不要使用那些不支持feature所指定功能的主函數。event_config_set_flag()用來告知Libevent在構建event_base的時候去設置1些運行時標志。
1些用在event_config_require_features的feature有:
EV_FEATURE_ET:要求主函數支持edge-triggered。(邊沿模式)
EV_FEATURE_O1:要求主函數增加,刪除event或某個event被激活的算法復雜度都是O(1)。
EV_FEATURE_FDS:要求主函數可以處理任意的文件描寫符,而不單單是socket。
event_config_set_flag使用到的值有:
EVENT_BASE_FLAG_NOLOCK:不給event_base分配鎖。設置這個選項可能為你節省1點花費在加鎖,解鎖上的時間,但是在多線程情況下,會變得不安全。
EVENT_BASE_FLAG_IGNORE_ENV:當選擇使用哪一個主函數時,不檢查EVENT_*的環境變量。使用前要想清楚,由于它會讓你在調試你的程序時,變得困難。
EVENT_BASE_FLAG_STARTUP_IOCP:只用在Windows上,在啟動時就啟用必要的IOCP邏輯調度。而不是按需。
EVENT_BASE_FLAG_NO_CACHE_TIME:不是在事件循環每次準備履行超時回調時檢測當前時間,而是在每次超時回調落后行檢測。注意,這會消耗更多的CPU時間。
EVENT_BASE_FLAG_EPOLL_USE_CHANGLIST:告知Libevent,如果使用的主函數是epoll,使用更高效的“changelist”模式。如果同1個fd的狀態在進入下1次循環前就被修改,epoll-changelist可以免沒必要要的系統調用。但要注意的是,如果Libevent使用的fd被dup()函數克隆,那它可能會觸發1個內核毛病。如果你沒有使用epoll,它是不起作用的。你可以通過設定EVENT_EPOLL_USE_CHANGLIST環境變量去啟用epoll-changelist。
EVENT_BASE_FLAG_PRECISE_TIMER:默許情況下,Libevent會嘗試去使用系統提供的效力最高的計時器。如果有1個計時器雖然比較慢,但是有更高的精確度。這個flag會讓Libevent去使用它。
接口
int event_config_set_num_cpus_hint(struct event_config *cfg, int cpus)
這個方法只在使用IOCP的Windows系統上有作用,固然在將來它也會被用在其他平臺上。調用它用來告知event_base充分使用給定數量的CPU。注:這只是1個提議,event_base可能會使用多于或少于你所給定的值。
接口
int event_config_set_max_dispatch_interval(struct event_config *cfg,
const struct timeval *max_interval, int max_callbacks,
int min_priority);
這個方法用來避免優先級反轉。它是通過限制在檢查高優先級event前,最多允許可被調用的低優先級event的數量來到達目的。如果max_interval非空,事件循環在每次回調后都會檢查時間。如果超過max_interval指定的時間,就會重新掃描高優先級的events。
如果max_callbacks非負,在max_callbacks調用被調用后,時間循環會繼續檢查更多的events。這些規則適用于任何高于min_priority的event。
例子:避免優先級反轉
struct event_config *cfg;
struct event_base *base;
cfg = event_config_new();
if (!cfg)
/* Handle error */;
/* I'm going to have events running at two priorities. I expect that
some of my priority⑴ events are going to have pretty slow callbacks,
so I don't want more than 100 msec to elapse (or 5 callbacks) before
checking for priority-0 events. */
struct timeval msec_100 = { 0, 100*1000 };
event_config_set_max_dispatch_interval(cfg, &msec_100, 5, 1);
base = event_base_new_with_config(cfg);
if (!base)
/* Handle error */;
event_base_priority_init(base, 2);
檢查某個event_base的主函數
某些時候,你想肯定1個event_base的支持那些特性,或它使用的是哪一個主函數,你可以:
接口
const char **event_get_supported_methods(void);
它返回1個指向方法名的數組的指針。最后1個元素為NULL。
例:
int i;
const char **methods = event_get_supported_methods();
printf("Starting Libevent %s. Available methods are:
",
event_get_version());
for (i=0; methods[i] != NULL; ++i) {
printf(" %s
", methods[i]);
}
接口
const char *event_base_get_method(const struct event_base *base);
enum event_method_feature event_base_get_features(const struct event_base *base);
event_base_get_method()函數返回當前正在被使用在event_base里面的主函數名字。event_base_get_features()函數它所支持的feature的按位與。
例:
struct event_base *base;
enum event_method_feature f;
base = event_base_new();
if (!base) {
puts("Couldn't get an event_base!");
} else {
printf("Using Libevent with backend method %s.",
event_base_get_method(base));
f = event_base_get_features(base);
if ((f & EV_FEATURE_ET))
printf(" Edge-triggered events are supported.");
if ((f & EV_FEATURE_O1))
printf(" O(1) event notification is supported.");
if ((f & EV_FEATURE_FDS))
printf(" All FD types are supported.");
puts("");
}
釋放event_base
當你結束使用event_base的時候,你可以通過調用event_base_free()釋放它。
接口
void event_base_free(struct event_base *base);
注:這個方法其實不釋放任何event_base所管理的events,也不會關閉它們的socket,或釋放它們的指針。
設置event_base的優先級
Libevent支持在1個event_base中設置多個優先級。默許它只支持1個基本的優先級。你可以通過調用event_base_priority_init()來設置優先級的數量。
接口
int event_base_priority_init(struct event_base *base, int n_priorities);
它成功返回0,失敗返回⑴。n_priorities是所設置的優先級的個數。它最小為1??捎玫膬炏燃壥菑?(優先級最高)到n_priorities⑴(優先級最低)。
它有個最大常量的限制EVENT_MAX_PRIORITIES。
注:這個方法必須在任何events被激活前被調用。最好在創建event_base后就調用它。
查看當前的event_base支持多少個優先級??捎谜{用:
接口
int event_base_get_npriorities(struct event_base *base);
默許情況下,所有新的event被分配的優先級會被初始化為當前event_base的n_priorities/2。
fork()后重新初始化event_base
在調用fork()后,event相干的數據可能變臟。所以,如果你想在fork后的進程中繼續使用event_base,你需要去重新初始化它。
接口
int event_reinit(struct event_base *base);
這個方法成功返回0,失敗返回⑴。
例:
struct event_base *base = event_base_new();
/* ... add some events to the event_base ... */
if (fork()) {
/* In parent */
continue_running_parent(base); /*...*/
} else {
/* In child */
event_reinit(base);
continue_running_child(base); /*...*/
}
生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈