epoll边缘触发_4.2.3、epoll:水平触发与边缘触发
select和poll都只提供了一個函數:select或者poll函數。
而epoll提供了三個函數,epoll_create,epoll_ctl和epoll_wait,epoll_create是創建一個epoll句柄;epoll_ctl是注冊要監聽的事件類型;epoll_wait則是等待事件的產生。
epoll除了提供select/poll那種IO事件的水平觸發(Level Triggered)外,還提供了邊緣觸發(Edge Triggered),這就使得用戶空間程序有可能緩存IO狀態,減少epoll_wait/epoll_pwait的調用,提高應用程序效率。
水平觸發(level-trggered)
只要文件描述符關聯的讀內核緩沖區非空,有數據可以讀取,就一直發出可讀信號進行通知,
當文件描述符關聯的內核寫緩沖區不滿,有空間可以寫入,就一直發出可寫信號進行通知
LT模式支持阻塞和非阻塞兩種方式。epoll默認的模式是LT。
邊緣觸發(edge-triggered)
當文件描述符關聯的讀內核緩沖區由空轉化為非空的時候,則發出可讀信號進行通知,
當文件描述符關聯的內核寫緩沖區由滿轉化為不滿的時候,則發出可寫信號進行通知
兩者的區別在哪里呢?水平觸發是只要讀緩沖區有數據,就會一直觸發可讀信號,而邊緣觸發僅僅在空變為非空的時候通知一次,
LT(level triggered)是缺省的工作方式,并且同時支持block和no-block socket.在這種做法中,內核告訴你一個文件描述符是否就緒了,然后你可以對這個就緒的fd進行IO操作。如果你不作任何操作,內核還是會繼續通知你的,所以,這種模式編程出錯誤可能性要小一點。傳統的select/poll都是這種模型的代表.
水平觸發和邊緣觸發模式區別
讀緩沖區剛開始是空的
讀緩沖區寫入2KB數據
水平觸發和邊緣觸發模式此時都會發出可讀信號
收到信號通知后,讀取了1kb的數據,讀緩沖區還剩余1KB數據
水平觸發會再次進行通知,而邊緣觸發不會再進行通知
所以,邊緣觸發需要一次性的把緩沖區的數據讀完為止,也就是一直讀,直到讀到EGAIN為止,EGAIN說明緩沖區已經空了,因為這一點,邊緣觸發需要設置文件句柄為非阻塞
//水平觸發
ret = read(fd, buf, sizeof(buf));
//邊緣觸發
while(true) {
ret = read(fd, buf, sizeof(buf);
if (ret == EAGAIN) break;
}
設置方法
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
epoll的事件注冊函數,它不同與select()是在監聽事件時告訴內核要監聽什么類型的事件,而是在這里先注冊要監聽的事件類型。
第一個參數是epoll_create()的返回值,
第二個參數表示動作,用三個宏來表示:
EPOLL_CTL_ADD:注冊新的fd到epfd中;
EPOLL_CTL_MOD:修改已經注冊的fd的監聽事件;
EPOLL_CTL_DEL:從epfd中刪除一個fd;
第三個參數是需要監聽的fd,第四個參數是告訴內核需要監聽什么事,struct epoll_event結構如下:
struct epoll_event {
__uint32_t events; /* Epoll events /
epoll_data_t data; / User data variable */
};
events可以是以下幾個宏的集合:
EPOLLIN :表示對應的文件描述符可以讀(包括對端SOCKET正常關閉);
EPOLLOUT:表示對應的文件描述符可以寫;
EPOLLPRI:表示對應的文件描述符有緊急的數據可讀(這里應該表示有帶外數據到來);
EPOLLERR:表示對應的文件描述符發生錯誤;
EPOLLHUP:表示對應的文件描述符被掛斷;
EPOLLET: 將EPOLL設為邊緣觸發(Edge Triggered)模式,這是相對于水平觸發(Level Triggered)來說的。
EPOLLONESHOT:只監聽一次事件,當監聽完這次事件之后,如果還需要繼續監聽這個socket的話,需要再次把這個socket加入到EPOLL隊列里。
使用示例
使用ET的例子:nginx
使用LT的例子:redis
總結
以上是生活随笔為你收集整理的epoll边缘触发_4.2.3、epoll:水平触发与边缘触发的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python代数式的表达方式_关于pyt
- 下一篇: android相册幻灯片功能,Andro