Libevent應用 (一) 建立event_base

嚇人的猿發表於2018-03-03

1 建立event_base

​ event_base算是Libevent最基礎、最重要的物件,因為修改配置、新增事件等,基本都需要將它作為引數傳遞進去。 

1.1建立預設的event_base

​ 這個物件通過event_base_new建立:

#include <event2/event.h>
struct event_base *event_base_new(void);

​ event_base_new()函式分配並且返回一個新的具有預設設定的event_base。函式會檢測環境變數,返回一個到event_base的指標。如果發生錯誤,則返回NULL。選擇各種方法時,函式會選擇OS支援的最快方法。

​ 使用完event_base之後,使用event_base_free()進行釋放。

void event_base_free(struct event_base *base);

注意:這個函式不會釋放當前與event_base關聯的任何事件,或者關閉他們的套接字,或者釋放任何指標。

編譯的時候需要加上-levent

1.2 檢查後端的方法

​ 有時候需要檢查event_base支援哪些特徵,或者當前使用哪種方法。

const char **event_get_supported_methods(void);
const char *event_get_version();

​ event_get_supported_methods()函式返回一個指標,指向libevent支援的方法名字陣列。這個陣列的最後一個元素是NULL。

#include <event2/event.h>
#include <stdio.h>
int main(void)
{
    int i = 0;
    const char **methods = event_get_supported_methods();
    printf("Starting Libevent %s.  Available methods are:\n", event_get_version());
    while(methods[i] != NULL) 
    {
        printf("%s\n", methods[i++]);
    }
}

1.3 建立複雜的event_base

​ 要對取得什麼型別的event_base有更多的控制,就需要使用event_config。event_config是一個容納event_base配置資訊的不透明結構體。需要event_base時,將event_config傳遞給event_base_new_with_config()。

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_base,先呼叫event_config_new()分配一個event_config。然後,對event_config呼叫其它函式,設定所需要的event_base特徵。最後,呼叫event_base_new_with_config()獲取新的event_base。完成工作後,使用event_config_free()釋放event_config。

1.3.1 禁用特定後端

​ 呼叫event_config_avoid_method()可以通過名字讓libevent避免使用特定的可用後端。成功時返回0,失敗時返回-1。

int event_config_avoid_method(struct event_config *cfg, const char *method);
const char* method;//指定特定的後端,例如"select" "poll" "epoll"

1.3.2 設定特徵

​ 呼叫event_config_require_feature()讓libevent不使用不能提供所有指定特徵的後端。成功時返回0,失敗時返回-1。

int event_config_require_features(struct event_config *cfg,
                                  enum event_method_feature feature);
enum event_method_feature {
    EV_FEATURE_ET = 0x01, //要求支援邊沿觸發的後端
    EV_FEATURE_O1 = 0x02, //要求新增、刪除單個事件,或者確定哪個事件啟用的操作是O(1)複雜度的後端
    EV_FEATURE_FDS = 0x04, //要求支援任意檔案描述符,而不僅僅是套接字的後端
};

注意:

​ 設定event_config,請求OS不能提供的後端是很容易的。

​ 比如說,對於libevent 2.0.1-alpha,在Windows中是沒有O(1)後端的;

​ 在Linux中也沒有同時提供EV_FEATURE_FDS和EV_FEATURE_O1特徵的後端。

​ 如果建立了libevent不能滿足的配置,event_base_new_with_config()會返回NULL。

1.3.3 設定標誌

​ 呼叫event_config_set_flag()讓libevent在建立event_base時設定一個或者多個將在下面介紹的執行時標誌。成功時返回0,失敗時返回-1。

int event_config_set_flag(struct event_config *cfg,
    enum event_base_config_flag flag);

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
};
EVENT_BASE_FLAG_NOLOCK://不要為event_base分配鎖。設定這個選項可以為event_base節省一點用於鎖定和解鎖的時間,但是讓在多個執行緒中訪問event_base成為不安全的。

EVENT_BASE_FLAG_IGNORE_ENV://選擇使用的後端時,不要檢測EVENT_*環境變數。使用這個標誌需要三思:這會讓使用者更難除錯你的程式與libevent的互動。

EVENT_BASE_FLAG_STARTUP_IOCP://僅用於Windows,讓libevent在啟動時就啟用任何必需的IOCP分發邏輯,而不是按需啟用。

EVENT_BASE_FLAG_NO_CACHE_TIME://不快取時間,在每個超時事件之後重新讀取系統時間. 
  
EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST://告訴libevent,如果決定使用epoll後端,可以安全地使用更快的基於changelist的後端。epoll-changelist後端可以在後端的分發函式呼叫之間,同樣的fd多次修改其狀態的情況下,避免不必要的系統呼叫。但是如果傳遞任何使用dup()或者其變體克隆的fd給libevent,epoll-changelist後端會觸發一個核心bug,導致不正確的結果。在不使用epoll後端的情況下,這個標誌是沒有效果的。也可以通過設定EVENT_EPOLL_USE_CHANGELIST環境變數來開啟epoll-changelist選項。

1.3.4 event_base優先順序

​ libevent支援為事件設定多個優先順序。然而,event_base預設只支援單個優先順序。可以呼叫event_base_priority_init()設定event_base的優先順序數目。

int event_base_priority_init(struct event_base *base, int n_priorities);

​ 成功時這個函式返回0,失敗時返回-1。base是要修改的event_base,n_priorities是要支援的優先順序數目,這個數目至少是1。每個新的事件可用的優先順序將從0(最高)到n_priorities-1(最低)。

​ 常量EVENT_MAX_PRIORITIES表示n_priorities的上限。呼叫這個函式時為n_priorities給出更大的值是錯誤的。

注意:

​ 必須在任何事件啟用之前呼叫這個函式,最好在建立event_base後立刻呼叫。

1.3.5 定製event_base程式碼

struct event_config *cfg;
struct event_base *base;

cfg = event_config_new();
event_config_avoid_method(cfg, "select");   //避免使用低效率select
event_config_require_features(cfg, EV_FEATURE_ET);  //使用具有邊沿觸發型別的後端
event_config_set_flag(cfg, EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST);
base = event_base_new_with_config(cfg);
event_config_free(cfg);

event_base_priority_init(base, 3); //設定優先順序
event_base_free(base);

1.3.6 檢查後端和特徵

​ event_base_get_method()返回event_base正在使用的方法。event_base_get_features()返回event_base支援的特徵的位元掩碼。

const char *event_base_get_method(const struct event_base *base);
enum event_method_feature event_base_get_features(const struct event_base *base);

示例程式碼如下:

#include <stdio.h>
#include <event2/event.h>
int main(void)
{
    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.\n", event_base_get_method(base));
        f = event_base_get_features(base);
        if ((f & EV_FEATURE_ET))
            printf("  Edge-triggered events are supported.\n");
        if ((f & EV_FEATURE_O1))
            printf("  O(1) event notification is supported.\n");
        if ((f & EV_FEATURE_FDS))
            printf("  All FD types are supported.\n");
        puts("");
    }
}

相關文章