2011-03-18 39 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