天天看點

徹底學會使用epoll(三)——ET的讀操作執行個體分析

首先看程式一,這個程式想要實作的功能是當使用者從控制台有任何輸入操作時,輸出”hello world!”。

l 程式一

點選(此處)折疊或打開

#include unistd.h>

#include iostream>

#include sys/epoll.h>

using namespace std;

int main(void)

{

    int epfd,nfds;

    struct epoll_event ev,events[5];//ev用于注冊事件,數組用于傳回要處理的事件

    epfd=epoll_create(1);//隻需要監聽一個描述符——标準輸入

    ev.data.fd=STDIN_FILENO;

    ev.events=EPOLLIN|EPOLLET;//監聽讀狀态同時設定ET模式

    epoll_ctl(epfd,EPOLL_CTL_ADD,STDIN_FILENO,&ev);//注冊epoll事件

    for(;;)

   {

     nfds=epoll_wait(epfd,events,5,-1);

     for(int i=0;infds;i++)

     {

        if(events[i].data.fd==STDIN_FILENO)

           cout"hello world!"endl;

     }

   }

}

運作結果:

徹底學會使用epoll(三)——ET的讀操作執行個體分析

程式一中對标準輸入的監聽使用ET模式,結果實作了我們想要的功能。那麼實際原理是如何呢,我們将過程分析一下:

(1) 當使用者輸入一組字元,這組字元被送入buffer,字元停留在buffer中,又因為buffer由空變為不空,是以ET傳回讀就緒,輸出”hello world!”。

(2) 之後程式再次執行epoll_wait,此時雖然buffer中有内容可讀,但是根據我們上節的分析,ET并不傳回就緒,導緻epoll_wait阻塞。(底層原因是ET下就緒fd的epitem隻被放入rdlist一次)。

(3) 使用者再次輸入一組字元,導緻buffer中的内容增多,根據我們上節的分析這将導緻fd狀态的改變,是對應的epitem再次加入rdlist,進而使epoll_wait傳回讀就緒,再次輸出“hello world!”。

 我們在看看LT的情況如何,将程式一以下修改:

    ev.events=EPOLLIN;//預設使用LT模式

徹底學會使用epoll(三)——ET的讀操作執行個體分析

結果正如我們所料,程式出現死循環,因為使用者輸入任意資料後,資料被送入buffer且沒有被讀出,是以LT模式下每次epoll_wait都認為buffer可讀傳回讀就緒。導緻每次都會輸出”hello world!”。下面在看程式二。

l 程式二

    char buf[256];

    ev.events=EPOLLIN;//使用預設LT模式

       if(events[i].data.fd==STDIN_FILENO)

       {

          read(STDIN_FILENO,buf,sizeof(buf));//将緩沖中的内容讀出

          cout"hello world!"endl;

       }

    }

  }

徹底學會使用epoll(三)——ET的讀操作執行個體分析

程式二依然使用LT模式,但是每次epoll_wait傳回讀就緒的時候我們都将buffer(緩沖)中的内容read出來,是以導緻buffer再次清空,下次調用epoll_wait就會阻塞。是以能夠實作我們所想要的功能——當使用者從控制台有任何輸入操作時,輸出”hello world!”。我們再來看看程式三。

l 程式三

    ev.events=EPOLLIN|EPOLLET;//使用預設LT模式

        {

          ev.data.fd=STDIN_FILENO;

          ev.events=EPOLLIN|EPOLLET;//使用預設LT模式

          epoll_ctl(epfd,EPOLL_CTL_MOD,STDIN_FILENO,&ev);//重新MOD事件(ADD無效)

        }

徹底學會使用epoll(三)——ET的讀操作執行個體分析

程式三依然使用ET,但是每次讀就緒後都主動的再次MOD IN事件,我們發現程式再次出現死循環,也就是每次傳回讀就緒。這就驗證了上一節讨論ET讀就緒的第三種情況。但是注意,如果我們将MOD改為ADD,将不會産生任何影響。别忘了每次ADD一個描述符都會在epitem組成的紅黑樹中添加一個項,我們之前已經ADD過一次,再次ADD将阻止添加,是以在次調用ADD IN事件不會有任何影響。

繼續閱讀