徹底學會使用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;i<nfds;i++)
-
{
-
if(events[i].data.fd==STDIN_FILENO)
-
cout<<"hello world!"<<endl;
-
}
-
}
- }
執行結果:
程式一中對標準輸入的監聽使用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模式
執行結果:
結果正如我們所料,程式出現死迴圈,因為使用者輸入任意資料後,資料被送入buffer且沒有被讀出,所以LT模式下每次epoll_wait都認為buffer可讀返回讀就緒。導致每次都會輸出”hello world!”。下面在看程式二。
l 程式二
點選(此處)摺疊或開啟
-
#include <unistd.h>
-
#include <iostream>
-
#include <sys/epoll.h>
-
using namespace std;
-
int main(void)
-
{
-
int epfd,nfds;
-
char buf[256];
-
struct epoll_event ev,events[5];//ev用於註冊事件,陣列用於返回要處理的事件
-
epfd=epoll_create(1);//只需要監聽一個描述符——標準輸入
-
ev.data.fd=STDIN_FILENO;
-
ev.events=EPOLLIN;//使用預設LT模式
-
epoll_ctl(epfd,EPOLL_CTL_ADD,STDIN_FILENO,&ev);//註冊epoll事件
-
for(;;)
-
{
-
nfds=epoll_wait(epfd,events,5,-1);
-
for(int i=0;i<nfds;i++)
-
{
-
if(events[i].data.fd==STDIN_FILENO)
-
{
-
read(STDIN_FILENO,buf,sizeof(buf));//將緩衝中的內容讀出
-
cout<<"hello world!"<<endl;
-
}
-
}
-
}
- }
執行結果:
程式二依然使用LT模式,但是每次epoll_wait返回讀就緒的時候我們都將buffer(緩衝)中的內容read出來,所以導致buffer再次清空,下次呼叫epoll_wait就會阻塞。所以能夠實現我們所想要的功能——當使用者從控制檯有任何輸入操作時,輸出”hello world!”。我們再來看看程式三。
l 程式三
點選(此處)摺疊或開啟
-
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;//使用預設LT模式
-
epoll_ctl(epfd,EPOLL_CTL_ADD,STDIN_FILENO,&ev);//註冊epoll事件
-
for(;;)
-
{
-
nfds=epoll_wait(epfd,events,5,-1);
-
for(int i=0;i<nfds;i++)
-
{
-
if(events[i].data.fd==STDIN_FILENO)
-
{
-
cout<<"hello world!"<<endl;
-
ev.data.fd=STDIN_FILENO;
-
ev.events=EPOLLIN|EPOLLET;//使用預設LT模式
-
epoll_ctl(epfd,EPOLL_CTL_MOD,STDIN_FILENO,&ev);//重新MOD事件(ADD無效)
-
}
-
}
-
}
- }
程式三依然使用ET,但是每次讀就緒後都主動的再次MOD IN事件,我們發現程式再次出現死迴圈,也就是每次返回讀就緒。這就驗證了上一節討論ET讀就緒的第三種情況。但是注意,如果我們將MOD改為ADD,將不會產生任何影響。別忘了每次ADD一個描述符都會在epitem組成的紅黑樹中新增一個項,我們之前已經ADD過一次,再次ADD將阻止新增,所以在次呼叫ADD IN事件不會有任何影響。
相關文章
- 徹底學會使用epoll(四)——ET的寫操作例項分析
- 徹底學會使用epoll(一)——ET模式實現分析模式
- 徹底學會使用epoll(五)—— ET模式下的注意事項模式
- 徹底學會使用epoll(六)——關於ET的若干問題總結
- 「linux」例項淺析epoll的LT和ET模式,ET模式為何要使用非阻塞IOLinux模式
- Epoll在LT和ET模式下的讀寫方式模式
- 【前端】一文徹底學會Promise前端Promise
- 30 個例項詳解 ,讓運維徹底搞清TOP 命令!運維
- 徹底學會 Go 指標 -- 就要學習 Go 語言Go指標
- ORACLE快速徹底Kill掉的會話Oracle會話
- 一文徹底熟練掌握並使用Java的NIO操作Java
- 徹底與加班說再見,藉助飛項學會任務管理,你也可以!
- JavaScript之例題中徹底理解thisJavaScript
- 用鬥地主的例項學會使用java Collections工具類Java
- 徹底搞懂Scrapy的中介軟體(三)
- 一文徹底弄懂Java的IO操作Java
- 「從原始碼中學習」徹底理解Vue選項Props原始碼Vue
- SAP徹底刪除物料主檔操作
- slub機制徹底圖解分析圖解
- 驗證.N“.NET研究”ET強命稱的思路和例項
- win10徹底禁用svchost如何操作 win10怎麼徹底關掉svchostWin10
- Java中Websocket使用例項解讀JavaWeb
- 三菱PLC例項學習
- SAP 徹底刪除物料主資料操作
- 徹徹底底教會你使用Redux-saga(包含樣例程式碼)Redux
- 【日誌技術專題】「logback入門到精通」徹徹底底帶你學會logback框架的使用和原理(入門介紹篇)框架
- 【轉】JAVA IO 設計模式徹底分析Java設計模式
- Python中逗號的三種作用例項分析Python
- 長尾理論的數學分析:真的徹底顛覆了二八法則?
- ET框架6.0分析三、網路通訊框架
- 如何使用CleanMyMac徹底擦除檔案?Mac
- 三消之王King的新遊戲徹底脫離了三消遊戲
- 萬字長文帶你徹底學會攔截器與過濾器過濾器
- 徹底學會element-ui按需引入和純淨主題定製UI
- golang 字串操作例項Golang字串
- expdp/impdp操作例項
- for迴圈的例項分析
- 例項教程:1小時學會PythonPython