epoll學習(二)

首先看程序一,這個程序想要實現的功能是當用戶從控制檯有任何輸入操做時,輸出hello worldios

程序一數組

 1     #include <unistd.h>
 2     #include <iostream>
 3     #include <sys/epoll.h>
 4     using namespace std;
 5     int main(void)
 6     {
 7         int epfd,nfds;
 8         struct epoll_event ev,events[5];//ev用於註冊事件,數組用於返回要處理的事件
 9         epfd=epoll_create(1);//只須要監聽一個描述符——標準輸入
10         ev.data.fd=STDIN_FILENO;
11         ev.events=EPOLLIN|EPOLLET;//監聽讀狀態同時設置ET模式
12         epoll_ctl(epfd,EPOLL_CTL_ADD,STDIN_FILENO,&ev);//註冊epoll事件
13         for(;;)
14        {
15          nfds=epoll_wait(epfd,events,5,-1);
16          for(int i=0;i<nfds;i++)
17          {
18             if(events[i].data.fd==STDIN_FILENO)
19                cout<<"hello world!"<<endl;
20          }
21        }
22     }

 

(1) 當用戶輸入一組字符,這組字符被送入buffer,字符停留在buffer中,又由於buffer由空變爲不空,因此ET返回讀就緒,輸出」hello world!」。spa

(2) 以後程序再次執行epoll_wait,此時雖然buffer中有內容可讀,可是根據咱們上節的分析,ET並不返回就緒,致使epoll_wait阻塞。(底層緣由是ET下就緒fd的epitem只被放入rdlist一次)。code

(3) 用戶再次輸入一組字符,致使buffer中的內容增多,根據咱們上節的分析這將致使fd狀態的改變,是對應的epitem再次加入rdlist,從而使epoll_wait返回讀就緒,再次輸出「hello world!」。blog

 

程序二事件

 

 1     #include <unistd.h>
 2     #include <iostream>
 3     #include <sys/epoll.h>
 4     using namespace std;
 5     int main(void)
 6     {
 7         int epfd,nfds;
 8         char buf[256];
 9         struct epoll_event ev,events[5];//ev用於註冊事件,數組用於返回要處理的事件
10         epfd=epoll_create(1);//只須要監聽一個描述符——標準輸入
11         ev.data.fd=STDIN_FILENO;
12         ev.events=EPOLLIN;//使用默認LT模式
13         epoll_ctl(epfd,EPOLL_CTL_ADD,STDIN_FILENO,&ev);//註冊epoll事件
14         for(;;)
15        {
16          nfds=epoll_wait(epfd,events,5,-1);
17          for(int i=0;i<nfds;i++)
18          {
19            if(events[i].data.fd==STDIN_FILENO)
20            {
21               read(STDIN_FILENO,buf,sizeof(buf));//將緩衝中的內容讀出
22               cout<<"hello world!"<<endl;
23            }
24         }
25       }
26     }

 

程序二依然使用LT模式,可是每次epoll_wait返回讀就緒的時候咱們都將buffer(緩衝)中的內容read出來,因此致使buffer再次清空,下次調用epoll_wait就會阻塞。因此可以實現咱們所想要的功能——當用戶從控制檯有任何輸入操做時,輸出hello worldit

 

 

程序三io

 

 1     int main(void)
 2     {
 3         int epfd,nfds;
 4         struct epoll_event ev,events[5];//ev用於註冊事件,數組用於返回要處理的事件
 5         epfd=epoll_create(1);//只須要監聽一個描述符——標準輸入
 6         ev.data.fd=STDIN_FILENO;
 7         ev.events=EPOLLIN|EPOLLET;//使用默認LT模式
 8         epoll_ctl(epfd,EPOLL_CTL_ADD,STDIN_FILENO,&ev);//註冊epoll事件
 9         for(;;)
10        {
11          nfds=epoll_wait(epfd,events,5,-1);
12          for(int i=0;i<nfds;i++)
13          {
14            if(events[i].data.fd==STDIN_FILENO)
15             {
16               cout<<"hello world!"<<endl;
17               ev.data.fd=STDIN_FILENO;
18               ev.events=EPOLLIN|EPOLLET;//使用默認LT模式
19               epoll_ctl(epfd,EPOLL_CTL_MOD,STDIN_FILENO,&ev);//從新MOD事件(ADD無效)
20             }
21          }
22        }
23     }

 

程序三依然使用ET,可是每次讀就緒後都主動的再次MOD IN事件,咱們發現程序再次出現死循環,也就是每次返回讀就緒。這就驗證了上一節討論ET讀就緒的第三種狀況。可是注意,若是咱們將MOD改成ADD,將不會產生任何影響。別忘了每次ADD一個描述符都會在epitem組成的紅黑樹中添加一個項,咱們以前已經ADD過一次,再次ADD將阻止添加,因此在次調用ADD IN事件不會有任何影響。event

 

程序四class

 

 

 1     #include <unistd.h>
 2     #include <iostream>
 3     #include <sys/epoll.h>
 4     using namespace std;
 5     int main(void)
 6     {
 7         int epfd,nfds;
 8         struct epoll_event ev,events[5];//ev用於註冊事件,數組用於返回要處理的事件
 9         epfd=epoll_create(1);//只須要監聽一個描述符——標準輸出
10         ev.data.fd=STDOUT_FILENO;
11         ev.events=EPOLLOUT|EPOLLET;//監聽讀狀態同時設置ET模式
12         epoll_ctl(epfd,EPOLL_CTL_ADD,STDOUT_FILENO,&ev);//註冊epoll事件
13         for(;;)
14        {
15           nfds=epoll_wait(epfd,events,5,-1);
16           for(int i=0;i<nfds;i++)
17          {
18              if(events[i].data.fd==STDOUT_FILENO)
19                  cout<<"hello world!"<<endl;
20          }
21        }
22     }

 

咱們發現這將是一個死循環。下面具體分析一下這個程序的執行過程:

 

(1) 首先初始buffer爲空,buffer中有空間可寫,這時不管是ET仍是LT都會將對應的epitem加入rdlist(對應第一節圖中的紅線),致使epoll_wait就返回寫就緒。

(2) 程序想標準輸出輸出hello world和換行符,由於標準輸出爲控制檯的時候緩衝是「行緩衝」,因此換行符致使buffer中的內容清空,這就對應第二節中ET模式下寫就緒的第二種狀況——當有舊數據被髮送走時,即buffer中待寫的內容變少得時候會觸發fd狀態的改變。因此下次epoll_wait會返回寫就緒。以後重複這個過程一直循環下去。

 

程序五

相對程序四這裏僅僅去掉了輸出的換行操做。即:

 cout<<"hello world!";

咱們看到程序成掛起狀態。由於第一次epoll_wait返回寫就緒後,程序向標準輸出的buffer中寫入「hello world!」,可是由於沒有輸出換行,因此buffer中的內容一直存在,下次epoll_wait的時候,雖然有寫空間可是ET模式下再也不返回寫就緒。回憶第一節關於ET的實現,這種狀況緣由就是第一次buffer爲空,致使epitem加入rdlist,返回一次就緒後移除此epitem,以後雖然buffer仍然可寫,可是因爲對應epitem已經再也不rdlist中,就不會對其就緒fdevents的在檢測了。

 

程序六

 

 1     int main(void)
 2     {
 3         int epfd,nfds;
 4         struct epoll_event ev,events[5];//ev用於註冊事件,數組用於返回要處理的事件
 5         epfd=epoll_create(1);//只須要監聽一個描述符——標準輸出
 6         ev.data.fd=STDOUT_FILENO;
 7         ev.events=EPOLLOUT;//使用默認LT模式
 8         epoll_ctl(epfd,EPOLL_CTL_ADD,STDOUT_FILENO,&ev);//註冊epoll事件
 9         for(;;)
10        {
11          nfds=epoll_wait(epfd,events,5,-1);
12          for(int i=0;i<nfds;i++)
13         {
14           if(events[i].data.fd==STDOUT_FILENO)
15              cout<<"hello world!";
16         }
17        }
18     };

 

程序六相對程序五僅僅是修改ET模式爲默認的LT模式,咱們發現程序再次死循環。這時候緣由已經很清楚了,由於當向buffer寫入hello world!後,雖然buffer沒有輸出清空,可是LT模式下只有buffer有寫空間就返回寫就緒,因此會一直輸出hello world!,buffer滿的時候,buffer會自動刷清輸出,一樣會形成epoll_wait返回寫就緒。

 

 

程序

 

 1     int main(void)
 2     {
 3         int epfd,nfds;
 4         struct epoll_event ev,events[5];//ev用於註冊事件,數組用於返回要處理的事件
 5         epfd=epoll_create(1);//只須要監聽一個描述符——標準輸出
 6         ev.data.fd=STDOUT_FILENO;
 7         ev.events=EPOLLOUT|EPOLLET;//監聽讀狀態同時設置ET模式
 8         epoll_ctl(epfd,EPOLL_CTL_ADD,STDOUT_FILENO,&ev);//註冊epoll事件
 9         for(;;)
10        {
11          nfds=epoll_wait(epfd,events,5,-1);
12          for(int i=0;i<nfds;i++)
13         {
14            if(events[i].data.fd==STDOUT_FILENO)
15                cout<<"hello world!";
16            ev.data.fd=STDOUT_FILENO; 
17            ev.events=EPOLLOUT|EPOLLET; 
18            epoll_ctl(epfd,EPOLL_CTL_MOD,STDOUT_FILENO,&ev); //從新MOD事件(ADD無效)
19        }
20      }
21     };

 

程序七相對於程序五在每次向標準輸出的buffer輸出」hello world!」後,從新MOD OUT事件。因此至關於每次從新進行第一節中紅線描述的途徑返回就緒,致使程序循環輸出。

相關文章
相關標籤/搜索