# 6.1 創建事件
##6.1.1 生成新事件
使用 event_new()接口創建事件。
```cpp
#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, short, void *);
struct event *event_new(struct event_base *base, evutil_socket_t fd,
short what, event_callback_fn cb,
void *arg);
void event_free(struct event *event);
```
event_new()試圖分配和構造一個用于 base 的新的事件。
what 參數是上述標志的集合。
如果 fd 非負,則它是將被觀察其讀寫事件的文件。
事件被激活時, libevent 將調用 cb 函數,
傳遞這些參數:文件描述符 fd,表示所有被觸發事件的位字段 ,以及構造事件時的 arg 參數。
發生內部錯誤,或者傳入無效參數時, event_new()將返回 NULL。
>所有新創建的事件都處于已初始化和非未決狀態 ,調用 event_add()可以使其成為未決的。
要釋放事件,調用 event_free()。對未決或者激活狀態的事件調用 event_free()是安全 的:在釋放事件之前,函數將會使事件成為非激活和非未決的。
###實例:
```cpp
#include <event2/event.h>
void cb_func(evutil_socket_t fd, short what, void *arg)
{
const char *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)
{
struct event *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 出現。
## 6.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版本開始就存在了。
## 6.1.3 關于事件持久性
默認情況下,每當未決事件成為激活的(因為 fd 已經準備好讀取或者寫入,或者因為超時), 事件將在其回調被執行前成為非未決的。如果想讓事件再次成為未決的 ,可以在回調函數中 再次對其調用 event_add()。
然而,如果設置了 EV_PERSIST 標志,事件就是持久的。這意味著即使其回調被激活 ,事件還是會保持為未決狀態 。如果想在回調中讓事件成為非未決的 ,可以對其調用 event_del ()。
每次執行事件回調的時候,持久事件的超時值會被復位。因此,如果具有 EV_READ|EV_PERSIST 標志,以及5秒的超時值,則事件將在以下情況下成為激活的:
* 套接字已經準備好被讀取的時候
* 從最后一次成為激活的開始,已經逝去 5秒
## 6.1.4 信號事件
libevent 也可以監測 POSIX 風格的信號。要構造信號處理器,使用:
```cpp
#define evsignal_new(base, signum, cb, arg) \
event_new(base, signum, EV_SIGNAL|EV_PERSIST, cb, arg)
```
除了提供一個信號編號代替文件描述符之外,各個參數與 event_new()相同。
###實例
```cpp
struct event *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 也提供了一組方便使用的宏用于處理信號事件:
```cpp
#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 Libevent官方
- 2 epoll
- 2.1 流-IO操作-阻塞
- 2.2 解決阻塞死等待的辦法
- 2.3 什么是epoll
- 2.4 epollAPI
- 2.5 觸發模式
- 2.6 簡單的epoll服務器
- 3 epoll和reactor
- 3.1 reactor反應堆模式
- 3.2 epoll的反應堆模式實現
- 4 event_base
- 4.1 創建event_base
- 4.2 檢查event_base后端
- 4.3 釋放event_base
- 4.4 event_base優先級
- 4.5 event_base和fork
- 5 事件循環event_loop
- 5.1 運行循環
- 5.2 停止循環
- 5.3 轉儲event_base的狀態
- 6 事件event
- 6.1 創建事件
- 6.2 事件的未決和非未決
- 6.3 事件的優先級
- 6.4 檢查事件狀態
- 6.5 一次觸發事件
- 6.6 手動激活事件
- 6.7 事件狀態之間的轉換
- 7 數據緩沖Bufferevent
- 7.1 回調和水位
- 7.2 延遲回調
- 7.3 bufferevent 選項標志
- 7.4 使用bufferevent
- 7.5 通用bufferevent操作
- 7.5.1 釋放bufferevent操作
- 7.5.2 操作回調、水位和啟用/禁用
- 7.5.3 操作bufferevent中的數據
- 7.5.4 bufferevent的清空操作
- 8 數據封裝evBuffer
- 8.1 創建和釋放evbuffer
- 8.2 evbuffer與線程安全
- 8.3 檢查evbuffer
- 8.4 向evbuffer添加數據
- 8.5 evbuffer數據移動
- 8.6 添加數據到evbuffer前
- 8 鏈接監聽器evconnlistener
- 8.1 創建和釋放 evconnlistener
- 8.2 啟用和禁用 evconnlistener
- 8.3 調整 evconnlistener 的回調函數
- 8.4 檢測 evconnlistener
- 8.5 偵測錯誤
- 9 libevent常用設置
- 9.1 日志消息回調設置
- 9.2 致命錯誤回調設置
- 9.3 內存管理回調設置
- 9.4 鎖和線程的設置
- 9.5 調試事件的使用
- 10 基于libevent服務器
- 10.1 Hello_World服務器(基于信號)
- 10.2 基于事件服務器
- 10.3 回顯服務器
- 10.3 libevent實現http服務器