2011-03-18 101 views
3

我正在寫一個基於epoll的簡單服務器類。爲了喚醒epoll_wait(),我決定使用eventfd。據說它更適合簡單的事件溝通,我同意這一點。所以,我建立了我的情況下,把手錶就可以了:linux - 無法讓eventfd一起使用epoll

_epollfd = epoll_create1(0); 
if (_epollfd == -1) throw ServerError("epoll_create"); 
_eventfd = eventfd(0, EFD_NONBLOCK); 
epoll_event evnt = {0}; 
evnt.data.fd = _eventfd; 
evnt.events = _events; 
if (epoll_ctl(_epollfd, EPOLL_CTL_ADD, _eventfd, &evnt) == -1) 
    throw ServerError("epoll_ctl(add)"); 

在消息等待循環後,在一個單獨的線程:

int count = epoll_wait(_epollfd, evnts, EVENTS, -1); 
    if (count == -1) 
    { 
     if (errno != EINTR) 
     { 
      perror("epoll_wait"); 
      return; 
     } 
    } 

    for (int i = 0; i < count; ++i) 
    { 
     epoll_event & e = evnts[i]; 
     if (e.data.fd == _serverSock) 
      connectionAccepted(); 
     else if (e.data.fd == _eventfd) 
     { 
      eventfd_t val; 
      eventfd_read(_eventfd, &val); 
      return; 
     } 
    } 

,當然,也停止服務器是代碼:

eventfd_write(_eventfd, 1); 

對於我無法解釋原因,我無法僅僅通過書面形式向事件喚醒epoll_wait()。最終,這在幾個調試會話中起作用。

這裏是我的解決辦法:知道EPOLLOUT會在每次fd是可用於寫入時間觸發一個事件,我改變了停止碼的

epoll_event evnt = {0}; 
evnt.data.fd = _eventfd; 
evnt.events = EPOLLOUT; 
if (epoll_ctl(_epollfd, EPOLL_CTL_MOD, _eventfd, &evnt) == -1) 
    throw ServerError("epoll_ctl(mod)"); 

現在,它的工作原理,但它不應該是這個樣子。

我不認爲這應該是困難的。我做錯了什麼?

謝謝

+1

什麼是'_events'初始化爲? – caf 2011-03-19 01:51:29

+0

_events被設置爲EPOLLIN | EPOLLET – user666412 2011-10-14 15:45:39

回答

2

適合我。作爲參考,這裏是完整的C代碼:它打印「eventfd_write」,「1」和「DING:1」。在Linux 2.6.35-30-generic#56-Ubuntu SMP上測試。

#include <stdio.h> 
#include <errno.h> 
#include <sys/epoll.h> 
#include <sys/eventfd.h> 
#include <pthread.h> 
#include <stdlib.h> 

int _epollfd, _eventfd; 

int init() 
{ 
    _epollfd = epoll_create1(0); 
    if (_epollfd == -1) abort(); 
    _eventfd = eventfd(0, EFD_NONBLOCK); 
    struct epoll_event evnt = {0}; 
    evnt.data.fd = _eventfd; 
    evnt.events = EPOLLIN | EPOLLET; 
    if (epoll_ctl(_epollfd, EPOLL_CTL_ADD, _eventfd, &evnt) == -1) 
     abort(); 
} 

void *subprocess(void *arg) 
{ 
    static const int EVENTS = 20; 
    struct epoll_event evnts[EVENTS]; 
    while (1) { 
     int count = epoll_wait(_epollfd, evnts, EVENTS, -1); 
     printf("%d\n", count); 
     if (count == -1) 
     { 
      if (errno != EINTR) 
      { 
       perror("epoll_wait"); 
       return NULL; 
      } 
     } 

     int i; 
     for (i = 0; i < count; ++i) 
     { 
      struct epoll_event *e = evnts + i; 
      if (e->data.fd == _eventfd) 
      { 
       eventfd_t val; 
       eventfd_read(_eventfd, &val); 
       printf("DING: %lld\n", (long long)val); 
       return NULL; 
      } 
     } 
    } 
} 

int main() 
{ 
    pthread_t th; 
    init(); 
    if (pthread_create(&th, NULL, subprocess, NULL) != 0) 
     abort(); 
    sleep(2); 
    printf("eventfd_write\n"); 
    eventfd_write(_eventfd, 1); 
    sleep(2); 
} 
+0

也適用於我(3.1.10-1.16-desktop#1 SMP PREEMPT)。我的發行版是OpenSuSE 11.3,我不確定我正在運行哪個內核... – user666412 2012-09-05 20:13:40

1

如果你使用多線程,你必須鏈中的每個線程結束呼叫eventfd_write。這只是一個選擇。

+0

這只是一個線程。在回到'epoll_wait()'之前,鏈接需要一個屏障,這樣一個線程不會醒來兩次,對吧? – user666412 2012-09-05 20:17:22