1. 程式人生 > >翻譯:libevent參考手冊第四章:與事件一起工作 (六) (轉)

翻譯:libevent參考手冊第四章:與事件一起工作 (六) (轉)

libevent的基本操作單元是事件。每個事件代表一組條件的集合,這些條件包括:

檔案描述符已經就緒,可以讀取或者寫入

檔案描述符變為就緒狀態,可以讀取或者寫入(僅對於邊沿觸發IO)

超時事件

發生某訊號

使用者觸發事件

所有事件具有相似的生命週期。呼叫libevent函式設定事件並且關聯到event_base之後,事件進入“已初始化(initialized)”狀態。此時可以將事件新增到event_base中,這使之進入“未決(pending)”狀態。在未決狀態下,如果觸發事件的條件發生(比如說,檔案描述符的狀態改變,或者超時時間到達),則事件進入“啟用(active)”狀態,(使用者提供的)事件回撥函式將被執行。如果配置為“

持久的(persistent)”,事件將保持為未決狀態。否則,執行完回撥後,事件不再是未決的。刪除操作可以讓未決事件成為非未決(已初始化)的;新增操作可以讓非未決事件再次成為未決的。

構造事件物件

1.1 建立事件

使用event_new()介面建立事件。

介面
#define EV_TIMEOUT      0x01#define EV_READ         0x02#define EV_WRITE        0x04#define EV_SIGNAL       0x08#define EV_PERSIST      0x10#define EV_ET           0x20

typedef 
void (*
event_callback_fn)(evutil_socket_t, shortvoid*);

structevent*event_new(struct event_base *base, evutil_socket_t fd,
    
short what, event_callback_fn cb,
    
void*arg);

void event_free(structevent*event);

event_new()試圖分配和構造一個用於base的新的事件。what引數是上述標誌的集合。如果fd非負,則它是將被觀察其讀寫事件的檔案。事件被啟用時,libevent將呼叫cb函式,傳遞這些引數:檔案描述符fd,表示所有被觸發事件的位欄位,以及構造事件時的arg引數。

發生內部錯誤,或者傳入無效引數時,event_new()將返回NULL。

所有新建立的事件都處於已初始化和非未決狀態,呼叫event_add()可以使其成為未決的。

要釋放事件,呼叫event_free()。對未決或者啟用狀態的事件呼叫event_free()是安全的:在釋放事件之前,函式將會使事件成為非啟用和非未決的。

示例

#include <event2/event.h>void cb_func(evutil_socket_t fd, short what, void*arg)
{
        
constchar*data = arg;
        printf(
"Got an event on socket %d:%s%s%s%s [%s]",
            (
int) fd,
            (what
&EV_TIMEOUT) ?" timeout" : "",
            (what
&EV_READ)    ?" read" : "",
            (what
&EV_WRITE)   ?" write" : "",
            (what
&EV_SIGNAL)  ?" signal" : "",
            data);
}

void main_loop(evutil_socket_t fd1, evutil_socket_t fd2)
{
        
structevent*ev1, *ev2;
        
struct timeval five_seconds = {5,0};
        
struct event_base *base= event_base_new();

        
/* The caller has already set up fd1, fd2 somehow, and make them
           nonblocking. 
*/

        ev1 
= event_new(base, fd1, EV_TIMEOUT|EV_READ|EV_PERSIST, cb_func,
           (
char*)"Reading event");
        ev2 
= event_new(base, fd2, EV_WRITE|EV_PERSIST, cb_func,
           (
char*)"Writing event");

        event_add(ev1, 
&five_seconds);
        event_add(ev2, NULL);
        event_base_dispatch(
base);
}

上述函式定義在<event2/event.h>中,首次出現在libevent 2.0.1-alpha版本中。event_callback_fn型別首次在2.0.4-alpha版本中作為typedef出現。

1.2 事件標誌

EV_TIMEOUT

這個標誌表示某超時時間流逝後事件成為啟用的。構造事件的時候,EV_TIMEOUT標誌是被忽略的:可以在新增事件的時候設定超時,也可以不設定。超時發生時,回撥函式的what引數將帶有這個標誌。

EV_READ

表示指定的檔案描述符已經就緒,可以讀取的時候,事件將成為啟用的。

EV_WRITE

表示指定的檔案描述符已經就緒,可以寫入的時候,事件將成為啟用的。

EV_SIGNAL

用於實現訊號檢測,請看下面的“構造訊號事件”節。

EV_PERSIST

表示事件是“持久的”,請看下面的“關於事件永續性”節。

EV_ET

表示如果底層的event_base後端支援邊沿觸發事件,則事件應該是邊沿觸發的。這個標誌影響EV_READ和EV_WRITE的語義。

從2.0.1-alpha版本開始,可以有任意多個事件因為同樣的條件而未決。比如說,可以有兩個事件因為某個給定的fd已經就緒,可以讀取而成為啟用的。這種情況下,多個事件回撥被執行的次序是不確定的。

這些標誌定義在<event2/event.h>中。除了EV_ET在2.0.1-alpha版本中引入外,所有標誌從1.0版本開始就存在了。

1.3 關於事件永續性

預設情況下,每當未決事件成為啟用的(因為fd已經準備好讀取或者寫入,或者因為超時),事件將在其回撥被執行前成為非未決的。如果想讓事件再次成為未決的,可以在回撥函式中再次對其呼叫event_add()。

然而,如果設定了EV_PERSIST標誌,事件就是持久的。這意味著即使其回撥被啟用,事件還是會保持為未決狀態。如果想在回撥中讓事件成為非未決的,可以對其呼叫event_del()。

每次執行事件回撥的時候,持久事件的超時值會被複位。因此,如果具有EV_READ|EV_PERSIST標誌,以及5秒的超時值,則事件將在以下情況下成為啟用的:

套接字已經準備好被讀取的時候

從最後一次成為啟用的開始,已經逝去5秒

1.4 只有超時的事件

為使用方便,libevent提供了一些以evtimer_開頭的巨集,用於替代event_*呼叫來操作純超時事件。使用這些巨集能改進程式碼的清晰性。

介面

#define evtimer_new(base, callback, arg) \
    event_new((
base), -10, (callback), (arg))
#define evtimer_add(ev, tv) \
    event_add((ev),(tv))
#define evtimer_del(ev) \
    event_del(ev)
#define evtimer_pending(ev, what, tv_out) \
    event_pending((ev), (what), (tv_out))

除了evtimer_new()首次出現在2.0.1-alpha版本中之外,這些巨集從0.6版本就存在了。

1.5 構造訊號事件

libevent也可以監測POSIX風格的訊號。要構造訊號處理器,使用:

介面

#define evsignal_new(base, signum, callback, arg) \
    event_new(
base, signum, EV_SIGNAL|EV_PERSIST, cb, arg)

除了提供一個訊號編號代替檔案描述符之外,各個引數與event_new()相同。

示例

structevent*hup_event;
struct event_base *base= event_base_new();

/* call sighup_function on a HUP signal */
hup_event 
= evsignal_new(base, SIGHUP, sighup_function, NULL);

注意:訊號回撥是訊號發生後在事件迴圈中被執行的,所以可以安全地呼叫通常不能在POSIX風格訊號處理器中使用的函式。

警告:不要在訊號事件上設定超時,這可能是不被支援的。[待修正:真是這樣的嗎?]

libevent也提供了一組方便使用的巨集用於處理訊號事件:

介面

#define evsignal_add(ev, tv) \
    event_add((ev),(tv))
#define evsignal_del(ev) \
    event_del(ev)
#define evsignal_pending(ev, what, tv_out) \
    event_pending((ev), (what), (tv_out))

evsignal_*巨集從2.0.1-alpha版本開始存在。先前版本中這些巨集叫做signal_add()、signal_del()等等。

關於訊號的警告

在當前版本的libevent和大多數後端中,每個程序任何時刻只能有一個event_base可以監聽訊號。如果同時向兩個event_base新增訊號事件,即使是不同的訊號,也只有一個event_base可以取得訊號。

kqueue後端沒有這個限制。

1.6 設定不使用堆分配的事件

出於效能考慮或者其他原因,有時需要將事件作為一個大結構體的一部分。對於每個事件的使用,這可以節省:

記憶體分配器在堆上分配小物件的開銷

對event結構體指標取值的時間開銷

如果事件不在快取中,因為可能的額外快取丟失而導致的時間開銷

對於大多數應用來說,這些開銷是非常小的。所以,除非確定在堆上分配事件導致了嚴重的效能問題,應該堅持使用event_new()。如果將來版本中的event結構體更大,不使用event_new()可能會導致難以診斷的錯誤。

不在堆上分配event具有破壞與其他版本libevent二進位制相容性的風險:其他版本中的event結構體大小可能不同。

介面

int event_assign(structevent*eventstruct event_base *base,
    evutil_socket_t fd, 
short what,
    
void (*callback)(evutil_socket_t, shortvoid*), void*arg);

除了event引數必須指向一個未初始化的事件之外,event_assign()的引數與event_new()的引數相同。成功時函式返回0,如果發生內部錯誤或者使用錯誤的引數,函式返回-1。

示例

#include <event2/event.h>/* Watch out!  Including event_struct.h means that your code will not
 * be binary-compatible with future versions of Libevent. 
*/
#include 
<event2/event_struct.h>
#include 
<stdlib.h>struct event_pair {
         evutil_socket_t fd;
         
structevent read_event;
         
structevent write_event;
};
void readcb(evutil_socket_t, shortvoid*);
void writecb(evutil_socket_t, shortvoid*);
struct event_pair *event_pair_new(struct event_base *base, evutil_socket_t fd)
{
        
struct event_pair *= malloc(sizeof(struct event_pair));
        
if (!p) return NULL;
        p
->fd = fd;
        event_assign(
&p->read_event, base, fd, EV_READ|EV_PERSIST, readcb, p);
        event_assign(
&p->write_event, base, fd, EV_WRITE|EV_PERSIST, writecb, p);
        
return p;
}

也可以用event_assign()初始化棧上分配的,或者靜態分配的事件。

警告

相關推薦

翻譯libevent參考手冊事件一起工作 ()

libevent的基本操作單元是事件。每個事件代表一組條件的集合,這些條件包括:v 檔案描述符已經就緒,可以讀取或者寫入v 檔案描述符變為就緒狀態,可以讀取或者寫入(僅對於邊沿觸發IO)v 超時事件v 發生某訊號v 使用者觸發事件所有事件具有相似的生命週期。呼叫libevent函式設定事件並且關聯到event

翻譯libevent參考手冊連線監聽器接受TCP連線 (十一) ()

#include <event2/listener.h>#include <event2/bufferevent.h>#include <event2/buffer.h>#include <arpa/inet.h>#include <string.h>

翻譯Libevent參考手冊事件迴圈一起工作 (五)

預設情況下,event_base_loop()函式執行event_base直到其中沒有已經註冊的事件為止。執行迴圈的時候,函式重複地檢查是否有任何已經註冊的事件被觸發(比如說,讀事件的檔案描述符已經就緒,可以讀取了;或者超時事件的超時時間即將到達)。如果有事件被觸發,函式標記被觸發的事件為“啟用的”,並且執行

翻譯libevent參考手冊Bufferevent高階話題 (九)

bufferevent_filter_new()函式建立一個封裝現有的“底層”bufferevent的過濾bufferevent。所有通過底層bufferevent接收的資料在到達過濾bufferevent之前都會經過“輸入”過濾器的轉換;所有通過底層bufferevent傳送的資料在被髮送到底層buffer

翻譯libevent參考手冊輔助型別和函式 (七) ()

這些巨集訪問和操作套接字錯誤程式碼。EVUTIL_SOCKET_ERROR()返回本執行緒最後一次套接字操作的全域性錯誤號,evutil_socket_geterror()則返回某特定套接字的錯誤號。(在類Unix系統中都是errno)EVUTIL_SET_SOCKET_ERROR()修改當前套接字錯誤號(與

翻譯libevent參考手冊evbuffer緩衝IO實用功能 (十)

{    /* Let's look at the first two chunks of buf, and write them to stderr. */int n, i;    struct evbuffer_iovec v[2];    n = evbuffer_peek(buf, -1, NULL,

翻譯libevent參考手冊bufferevent概念和入門 (八)

bufferevent_setcb()函式修改bufferevent的一個或者多個回撥。readcb、writecb和eventcb函式將分別在已經讀取足夠的資料、已經寫入足夠的資料,或者發生錯誤時被呼叫。每個回撥函式的第一個引數都是發生了事件的bufferevent,最後一個引數都是呼叫buffereven

開始Unity Shader學習之旅3

行處理 由於 ctx 渲染 ima arc bubuko 這一 vpd 1. 程序員的煩惱:Debug 調試(debug),大概是所有程序員的噩夢。而不幸的是,對一個Shader進行調試更是噩夢中的噩夢。這也是造成Shader難寫的原因之一——如果發現得到的效果不對,我們就

翻譯libevent參考手冊第二建立event_base ()

呼叫event_config_avoid_method()可以通過名字讓libevent避免使用特定的可用後端。呼叫event_config_require_feature()讓libevent不使用不能提供所有指定特徵的後端。呼叫event_config_set_flag()讓libevent在建立even

翻譯Libevent參考手冊第一設定libevent (三)

evthread_lock_callbacks結構體描述的鎖回撥函式及其能力。對於上述版本,lock_api_version欄位必須設定為EVTHREAD_LOCK_API_VERSION。必須設定supported_locktypes欄位為EVTHREAD_LOCKTYPE_*常量的組合以描述支援的鎖型別(

翻譯Libevent參考手冊前言 (二)

1  從一萬英尺外看LibeventLibevent是用於編寫高速可移植非阻塞IO應用的庫,其設計目標是:v 可移植性:使用libevent編寫的程式應該可以在libevent支援的所有平臺上工作。即使沒有好的方式進行非阻塞IO,libevent也應該支援一般的方式,讓程式可以在受限的環境中執行。v 速度:l

Netty In Action中文版 - Transports(傳輸)

duplicate pipeline 客戶 下列表 bytes 線程安全 get 工具 jsb 本章內容 Transports(傳輸)NIO(non-blocking IO,New IO), OIO(Old IO,blocking IO), Local(本地),

讀構建之法 兩人合作

應用 結對編程 使用 一對一 測試 一個 比較 以及 領域 程序員寫的代碼最終是人在看,所以代碼規範很重要,原則是:簡明,易讀,無二義性。 不光是程序書寫的格式問題,還牽涉到程序設計、模塊之間的關系、設計模式等方方面面。 代碼復審的正確定義看代碼是否在代碼規範的框架內正確的

執行環境作用域

logs 執行 引用傳遞 按值傳遞 ons fun col func clas 函數中對象的值是按值傳遞的 !(function () { //對象的按值傳遞or按引用傳遞在函數中 function setName(obj) {

操作列表

clas str 3.3 轉換 一個 改變 導致 賦值 any 第四章:操作列表 4.1 遍歷整個列表 如果名單很長,將包含大量反復的代碼。另外,每當名單的長度發生變化時,都必須修改代碼。通過for 循環,可讓Python去處理這些問題 1)使用for循環來打印魔術師名

重構代碼[學習Android Studio漢化教程]

出現 introduce 編輯 rri 分享 成員 dialog fig ice 第四章 Refactoring Code The solutions you develop in Android Studio will not always follow a straig

ES6標準入門 字符串的擴展

固定 缺陷 長度 需要 允許 實例對象 poi turn har 1、字符串的Unicode 表示法 JavaScript 允許采用 \uxxxx 表示一個字符,其中 xxxx 表示字符的碼點。 "\u0061" // "a" ES5中的缺陷: 以上表示

Node入門教程(5)global 全局變量

-c 這不 .com clear 替換 http htm 取消 floating global - 全局變量 全局對象(global object),不要和 全局的對象( global objects )或稱標準內置對象混淆。這裏說的全局的對象是說在全局作用域裏的內的對象

活動圖

分享圖片 只有一個 什麽 分叉 img 面向 png 對象流 有一個 活動圖明確先做什麽,後坐什麽,什麽條件下做什麽。 活動圖也可以不面向對象,但流程圖一定面向過程。 一個活動圖一定有只有一個初始節點。終點為1~n。 如果有多個終點那麽可以有描述。

Spring AOP

edi 關註 aspectj 附加 aop 插入 out cert AC 4.1:面向切面編程 AOP是在運行期間將代碼切入到類的指定位置的編程思想。切面能幫助我們模塊化橫切關註點,實現橫切關註點的復用。Spring在運行期間將切面植入到指定的Bean中,實際是通過攔