epoll的兩種模式


從代碼開始吧:

epoll_ctl(clifd, EPOLL_CTL_ADD, EPOLLIN | EPOLLOUT);

epoll主循環將使用水平模式(默認,EPOLLLT)監聽clifd的讀寫狀態,在水平模式下,只要clifd的內核讀緩沖區存在未讀的數據,每一次的epoll_wait()返回針對clifd的epoll_event都會設置EPOLLIN;只要clifd的內核寫緩沖區存在可寫空間,每一次的epoll_wait()返回針對clifd的epoll_event都會設置EPOLLOUT。通常來說,讀光內核緩沖區不難,寫滿內核緩沖區就有點扯了。通常的解決方案是:

Don't include EPOLLOUT unless you got EAGAIN from a write attempt, and remove it when you have successfully written bytes to a socket.

例如在一個epoll循環內,監聽readfd的讀事件,將從readfd中獲得的數據完整寫到writefd中,當write()並未完整執行時,監聽writefd的寫事件:

 1 while (1) 
 2 {
 3     int n, i;
 4     n = epoll_wait(epoll_fd, events, 8192, -1);
 5 
 6     for (i = 0; i < n; i++)
 7     {   
 8         int fd = events[i].data.fd;
 9 
10         if (events[i].events & EPOLLOUT)
11         {   
12             // ...
13             // 找到在NonBlockSend中的緩存buf
14             int nwrite = write(fd, buf, len);
15             if (nwrite == len)
16                 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, NULL);
17             else
18                 // 更新buf
19         }   
20 
21         if (events[i].events & EPOLLIN)
22         {   
23             char buf[1024];
24             int len = read(fd, buf, sizeof(buf));
25 
26             int nwrite = write(writefd, buf, len);
if (len == nwrite)
            return;
27 if (-1 == nwrite && EAGAIN != errno) 28 { 29 close(writefd); 30 } 31 else 32 { 33 nwrite = nwrite == -1 ? 0 : nwrite; 34 NonBlockSend(writefd, buf + nwrite, len - nwrite); 35 } 36 } 37 } 38 }

 

其中NonBlockSend()就是將數據存入writefd對應的緩沖區中,並為writefd建立EPOLLOUT事件監聽。恩,看起來沒什么問題了。但是,我也是剛剛才發現,問題還是有的。想象一下,某一次epoll_wait()返回writefd寫事件,針對writefd的write()調用將會成功,然而,假如同時觸發的還有readfd的讀事件,並且該事件先於writefd寫事件處理,那么,從readfd中讀到的新數據將先於已緩存的舊數據發送。。。。所以,處理readfd的讀事件,應該先判斷writefd是否已有緩存數據,是則直接調用NonBlockSend()。

不斷修改epoll的監聽事件集合好像不太好,於是我就想能否用一下邊緣模式(EPOLLET),因為在該模式下,只有當writefd從不可寫變為可寫時,epoll_wait()才會通知writefd的寫事件,也就是說,直到你再次把緩沖區寫滿后,epoll_wait()的返回才有可能包含writefd。對上面簡單的應用場合,使用EPOLLET是合情合理的,只需要把15至17行刪掉,然后從一開始就為writefd建立EPOLLOUT事件監聽,而不是放到NonBlockSend()里。

附幾篇關於epoll兩種模式的介紹:

http://stackoverflow.com/questions/12892286/epoll-with-edge-triggered-event/12897334#12897334

http://stackoverflow.com/questions/9162712/what-is-the-purpose-of-epolls-edge-triggered-option

http://www.ccvita.com/515.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM