Linux面試必知: 一句話講透epoll
epoll概念
在Linux的Man文檔中,我們可以看到如下定義
Epoll - I/O event notification facility
翻譯一下,epoll是一種I/O事件通知機制,這句話基本上包含了所有需要理解的要點
I/O事件
基於file descriptor,支持file, socket, pipe等各種I/O方式
當文件描述符關聯的內核讀緩衝區可讀,則觸發可讀事件,什麼是可讀呢?就是內核緩衝區非空,有數據可以讀取
當文件描述符關聯的內核寫緩衝區可寫,則觸發可寫事件,什麼是可寫呢?就是內核緩衝區不滿,有空閒空間可以寫入
通知機制
通知機制,就是當事件發生的時候,去通知他
通知機制的反面,就是輪詢機制
以上兩點結合起來理解
epoll是一種當文件描述符的內核緩衝區非空的時候,發出可讀信號進行通知,當寫緩衝區不滿的時候,發出可寫信號通知的機制
水平觸發與邊緣觸發
水平觸發(level-trggered)
只要文件描述符關聯的讀內核緩衝區非空,有數據可以讀取,就一直髮出可讀信號進行通知,
當文件描述符關聯的內核寫緩衝區不滿,有空間可以寫入,就一直髮出可寫信號進行通知
邊緣觸發(edge-triggered)
當文件描述符關聯的讀內核緩衝區由空轉化爲非空的時候,則發出可讀信號進行通知,
當文件描述符關聯的內核寫緩衝區由滿轉化爲不滿的時候,則發出可寫信號進行通知
兩者的區別在哪裏呢?水平觸發是隻要讀緩衝區有數據,就會一直觸發可讀信號,而邊緣觸發僅僅在空變爲非空的時候通知一次,舉個例子:
讀緩衝區剛開始是空的
讀緩衝區寫入2KB數據
水平觸發和邊緣觸發模式此時都會發出可讀信號
收到信號通知後,讀取了1kb的數據,讀緩衝區還剩餘1KB數據
水平觸發會再次進行通知,而邊緣觸發不會再進行通知
所以邊緣觸發需要一次性的把緩衝區的數據讀完爲止,也就是一直讀,直到讀到EGAIN爲止,EGAIN說明緩衝區已經空了,因爲這一點,邊緣觸發需要設置文件句柄爲非阻塞
//水平觸發
ret = read(fd, buf, sizeof(buf));
//邊緣觸發
while(true) {
ret = read(fd, buf, sizeof(buf);
if (ret == EAGAIN) break;
}
1
2
3
4
5
6
7
8
epoll接口介紹
epoll_create
創建epoll實例,會創建所需要的紅黑樹,以及就緒鏈表,以及代表epoll實例的文件句柄
函數原型: int epoll_create(int size);
Man文檔中說明了在老的內核版本中,入參size用來指出創建的內部數據結構的大小,目前已經可以動態調整,但是爲了兼容老的版本,所以仍然保留,這個size其實意義已經不大
epoll_ctl
添加,修改,或者刪除 註冊到epoll實例中的文件描述符上的監控事件
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
epfd: epoll實例file descriptor
op:操作類型
EPOLL_CTL_ADD, 爲相應fd添加事件
EPOLL_CTL_MOD, 修改fd的事件
EPOLL_CTL_DEL,刪除fd上的某些事件
1
2
3
fd: 操作的目標文件描述符
event: 要操作的事件
typedef union epoll_data {
void *ptr;
int fd;
uint32_t u32;
uint64_t u64;
} epoll_data_t;
struct epoll_event {
uint32_t events; /* Epoll events */
epoll_data_t data; /* User data variable */
};
events可以是一組bit的組合
EPOLLIN:可讀
EPOLLOUT: 可寫
EPOLLET: 邊緣觸發,默認是水平觸發
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
一句話來描述:就是對於註冊到epfd中的fd文件描述符,執行op event的操作
epoll_wait
epoll_wait等待epoll實例中註冊的事件觸發
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout)
epfd: epoll實例文件描述符
events: 數組出參,用來記錄被觸發的events,其大小應該和maxevents一致
maxevents: 返回的events的最大個數,如果最大個數大於實際觸發的個數,則下次epoll_wait的時候仍然可以返回
timeout: 等待事件,毫秒爲單位 -1:無限等待 0:立即返回