本文主要講述如何使用epoll來監聽timerfd系列函式建立的定時器,關於timerfd系列函式的使用請看這篇文章。
epoll_create()或epoll_create1():建立乙個epoll物件,並返回乙個檔案描述符指向這個epoll物件
epoll_ctl():新增想要監聽的檔案描述符
epoll_wait():等待i/o事件的發生,如果沒有事件發生就會阻塞呼叫執行緒
這3個api的原型如下,
#include
intepoll_create
(int size)
;// 舊版,size取值必須大於0
intepoll_create1
(int flags)
;// 新版,flags可以是0,或者epoll_cloexec
intepoll_ctl
(int epfd,
int op,
int fd,
struct epoll_event *event)
;int
epoll_wait
(int epfd,
struct epoll_event *events,
int maxevents,
int timeout)
;
關鍵結構體是struct epoll_event,其定義如下,
struct epoll_event
;typedef
union epoll_data epoll_data_t;
edge-triggered和level-triggered
epoll api可以使用edge-triggered或level-triggered的方式來監聽檔案描述符,可以翻譯為邊沿觸發和電平觸發,學過數位電路的比較好理解,如下圖
綠色的部分屬於電平觸發,當處於高電平或低電平時就會觸發;橘黃色屬於邊沿觸發,當電平發生由高變到低或者由低變成高就會觸發。
這裡再使用linux man手冊裡舉的例子來解釋一下,現在有乙個pipe,用於2個程序間進行通訊,乙個程序負責讀,另外的程序負責寫。操作如下,
讀程序把pipe對應的檔案描述符rfd新增到epoll裡進行監聽
寫程序往pipe裡寫了2kb的資料
讀程序裡的epoll_wait監聽到有資料進來,把rfd作為ready的描述符返回
讀程序通過rfd讀取1kb資料
epoll_wait繼續監聽rfd
如果在第1步裡使用的是邊沿觸發的方式監聽rfd,那麼第5步裡的epoll_wait就不會再把rfd作為ready的描述符返回,這樣讀程序就無法讀取剩餘的1kb資料了。如果使用的是電平觸發,就可以繼續讀取剩餘1kb資料,這是為什麼?
對於讀程序來說,初始時,buffer為空,可以看做電平為0狀態,當寫程序寫入資料後,buffer裡就會有資料,這樣buffer狀態發生變化,此時可以看做是電平1的狀態,這樣就發生了電平由0到1的變化,如果採用的是邊沿觸發,就會觸發,rfd就會作為ready的描述符返回。但是一次並沒有讀取完,buffer裡還有剩餘資料,那麼此時還是處於電平1狀態,這樣的話再次epoll_wait就不會觸發,因為電平狀態沒有發生變化。
但是如果使用電平觸發,buffer裡有資料就觸發,即電平為1就觸發,那麼當buffer由空變成有資料狀態,就會觸發,而且一次沒讀完,再次進入epoll_wait時還會觸發,直到把資料讀完,buffer變成空,就不再觸發了。
epoll預設使用電平觸發。
原始碼如下,
#include
#include
#include
#include
#include
#include
#include
#define handle_error(msg) \
do while (0)
void
print_elapsed_time
(void);
intmain
(void
)struct itimerspec new_value =
; new_value.it_value.tv_sec =1;
// 第一次1s到期
new_value.it_value.tv_nsec =0;
new_value.it_interval.tv_sec =5;
// 後續週期是5s cycle
new_value.it_interval.tv_nsec =0;
if(timerfd_settime
(timerfd,0,
&new_value,
null)==
-1)print_elapsed_time()
;printf
("timer started\n");
int epollfd =
epoll_create1
(epoll_cloexec)
;// or epoll_create(1)
if(epollfd ==-1
)struct epoll_event ev;
ev.events = epollin;
// 表示該檔案描述符可以讀的時候就觸發
ev.data.fd = timerfd;
epoll_ctl
(epollfd, epoll_ctl_add, timerfd,
&ev)
;const
int maxevents =5;
// 也可以設定為1
struct epoll_event events[maxevents]
;while(1
)print_elapsed_time()
;}}}
}return0;
}void
print_elapsed_time
(void);
static
int first_call =1;
if(first_call ==1)
}struct timeval current =;if
(gettimeofday
(¤t,
null)==
-1)static
int old_secs =
0, old_usecs =0;
int secs = current.tv_sec - start.tv_sec;
int usecs = current.tv_usec - start.tv_usec;
if(usecs <0)
usecs =
(usecs +
500)
/1000
;// 四捨五入
if(secs != old_secs || usecs != old_usecs)
}
比較關鍵的地方就是epollin這個引數,表示當檔案描述符可讀的時候觸發,這裡表示定時器到期時檔案描述符就會變成可讀,就會觸發。
執行結果如下,
定時器第一次到期時間是1s,後面迴圈週期是5s,和**裡設定的一樣。
epoll監聽檔案 epoll的使用
epoll i o event notification facility 在linux的網路程式設計中,很長的時間都在使用select來做事件觸發。在linux新的核心中,有了一種替換它的機制,就是epoll。相比於select,epoll最大的好處在於它不會隨著監聽fd數目的增長而降低效率。因為...
epoll監聽檔案 Epoll的簡介及原理
epoll 全稱 eventpoll,是 linux 核心實現io多路復用 io multiplexing 的乙個實現。io多路復用的意思是在乙個操作裡同時監聽多個輸入輸出源,在其中乙個或多個輸入輸出源可用的時候返回,然後對其的進行讀寫操作。在 linux 中,和 epoll 類似的有 select...
linux下的epoll函式
epoll是tcp ip網路程式設計的io服用方法之中一種優於select的函式,相比select,它有兩個優點 1.無需編寫以監視狀態變化為目的的針對所有檔案描述符的迴圈語句。2.呼叫對應於select函式的epoll wait函式時無需每次傳遞監視物件資訊。下面介紹epoll伺服器端實現中需要的...