EPOLLET vs. EPOLLLT
人果然是很懶的,一轉眼,就有好長一段時間沒有發文了。這倒不是說沒有值得紀錄的事情,而是「懶」。其實本來這裡也是給自己看的而已,但還是希望能養成良好的紀錄習慣囉。
上一篇文章是關於 epoll 的範例。 epoll 在運作上有兩種模式,EPOLLET(Edge-Triggered)和 EPOLLLT(Level-Triggered)。其實我完全不知道這個名字是怎麼來的。但姑且不管名字的由來,在使用上還是要知道這兩者的差異。
先從簡單的說起,EPOLLLT 在運作上可以視做是一個比較快的POLL(這可是官方文件說的)。只要 FD 裏面還有資料可以讀取,早晚都會被 polling 到。
上面好像是廢話,那 EPOLLET 有什麼不一樣呢?當有 FD 有資料可以被存取的時候,EPOLLET 運作模式會發一個 event 出來,提醒使用者去存取資料。注意,只會發一次唷。意思是,如果你的資料沒有存取完畢,它也不會再發一次事件來通知。我們就參考下面來自 man 的情境會更容易了解:
1. The file descriptor that represents the read side of a pipe (rfd) is registered on the epoll instance.
2. A pipe writer writes 2 kB of data on the write side of the pipe.
3. A call to epoll_wait(2) is done that will return rfd as a ready file descriptor.
4. The pipe reader reads 1 kB of data from rfd.
5. A call to epoll_wait(2) is done.
重點在步驟 4,就算你已經讀了 1kB,意味著還有 1kB 的資料需要讀取,epoll_wait 並不會再次送出通知而會停在那邊等待。這是因為 EPOLLET 發出事件通知的條件是 FD 的狀態發生改變。如果沒有改變,就算仍有資料要讀取,也不會有任何通知送出來。
那要如何避免這個狀況?第一,使用 EPOLLLT,這是預設的作法,但老實說,因為底層還是使用 polling ,所以效能比不上 EPOLLET。第二,透過 EAGAIN。作法很簡單,可以參考下面的程式:
不曉得下一篇會多久以後才寫 ...
修正:
之前請同事用這個方法來撰寫,實驗結果卻不是這樣,因為還是會停在 recv 無窮回圈裏面,理由是,這個 socket 並沒有被設成 Non-Blocking!!要將 Socket 設成 Non-blocking 可以用下面的函式:
上一篇文章是關於 epoll 的範例。 epoll 在運作上有兩種模式,EPOLLET(Edge-Triggered)和 EPOLLLT(Level-Triggered)。其實我完全不知道這個名字是怎麼來的。但姑且不管名字的由來,在使用上還是要知道這兩者的差異。
先從簡單的說起,EPOLLLT 在運作上可以視做是一個比較快的POLL(這可是官方文件說的)。只要 FD 裏面還有資料可以讀取,早晚都會被 polling 到。
上面好像是廢話,那 EPOLLET 有什麼不一樣呢?當有 FD 有資料可以被存取的時候,EPOLLET 運作模式會發一個 event 出來,提醒使用者去存取資料。注意,只會發一次唷。意思是,如果你的資料沒有存取完畢,它也不會再發一次事件來通知。我們就參考下面來自 man 的情境會更容易了解:
1. The file descriptor that represents the read side of a pipe (rfd) is registered on the epoll instance.
2. A pipe writer writes 2 kB of data on the write side of the pipe.
3. A call to epoll_wait(2) is done that will return rfd as a ready file descriptor.
4. The pipe reader reads 1 kB of data from rfd.
5. A call to epoll_wait(2) is done.
重點在步驟 4,就算你已經讀了 1kB,意味著還有 1kB 的資料需要讀取,epoll_wait 並不會再次送出通知而會停在那邊等待。這是因為 EPOLLET 發出事件通知的條件是 FD 的狀態發生改變。如果沒有改變,就算仍有資料要讀取,也不會有任何通知送出來。
那要如何避免這個狀況?第一,使用 EPOLLLT,這是預設的作法,但老實說,因為底層還是使用 polling ,所以效能比不上 EPOLLET。第二,透過 EAGAIN。作法很簡單,可以參考下面的程式:
while(1) { num = recvfrom( fd, buf, BUFFER_SIZE, 0 (struct sockaddr *)&srcAddr, $srcInfoLen ); if( num < 0 ) { break; } } if( errno != EAGAIN ) { return -1; }
在這裡 EAGAIN 代表的意思是這個 FD目前沒有資料可以讀取了,而且 FD 還在正常運作中的意思。
不曉得下一篇會多久以後才寫 ...
修正:
之前請同事用這個方法來撰寫,實驗結果卻不是這樣,因為還是會停在 recv 無窮回圈裏面,理由是,這個 socket 並沒有被設成 Non-Blocking!!要將 Socket 設成 Non-blocking 可以用下面的函式:
static int make_socket_non_blocking (int sfd) { int flags, s; flags = fcntl (sfd, F_GETFL, 0); if (flags == -1) { perror ("fcntl"); return -1; } flags |= O_NONBLOCK; s = fcntl (sfd, F_SETFL, flags); if (s == -1) { perror ("fcntl"); return -1; } return 0; }
留言
張貼留言