我希望通过eventfd在线程之间传输数据。 所以我写下面的代码来满足我的需要。 我的主机操作系统是openSUSE v12.3 64位。
#include "stdio.h" #include "unistd.h" #include "pthread.h" #include "sys/eventfd.h" #include "sys/epoll.h" #define nil NULL int efd = -1; void* read_thread(void* arg) { int ret = 0; uint64_t count = 0; int ep_fd = -1; struct epoll_event events[10]; (void)(arg); if (efd < 0) { printf("efd not inited.\n"); return nil; } ep_fd = epoll_create(1024); if (ep_fd < 0) { perror("epoll_create fail: "); return nil; } { struct epoll_event read_event; read_event.events = EPOLLIN; read_event.data.fd = efd; ret = epoll_ctl(ep_fd, EPOLL_CTL_ADD, efd, &read_event); if (ret < 0) { perror("epoll ctl failed:"); return nil; } } while (1) { ret = epoll_wait(ep_fd, events, 10, 5000); if (ret > 0) { int i = 0; for (i = 0; i < ret; i++) { if (events[i].events & (EPOLLHUP | EPOLLERR)) { printf("epoll eventfd has epoll hup.\n"); break; } else if (events[i].events & EPOLLIN) { int event_fd = events[i].data.fd; ret = eventfd_read(event_fd, &count); if (ret < 0) { perror("read fail:"); break; } else { printf("read %llu\n", count); } } } } else if (ret == 0) { break; } else { perror("epoll wait error:"); break; } } close(ep_fd); return nil; } int main(int argc, char *argv[]) { pthread_t pid = 0; uint64_t count = 0; int ret = 0; int i = 0; efd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); if (efd < 0) { perror("eventfd failed."); return -1; } ret = pthread_create(&pid, NULL, read_thread, NULL); if (ret < 0) { perror("pthread create:"); close(efd); return -2; } for (i = 0; i < 5; i++) { count = i + 1; ret = eventfd_write(efd, count); if (ret < 0) { perror("write event fd fail:"); break; } else { printf("write %llu\n", count); } } sleep(3); pthread_join(pid, NULL); close(efd); efd = -1; return 0; }
我认为eventfd的行为应该像一个pipe道。 所以程序的输出结果可能如下:
写1读1写2读2写3读3写4读4写5读5
但是,其实际结果是:
写1写2写3写4写5读15
要么
写1写2写3写4写5读1读14
一些好人能告诉我为什么输出结果是input结果的总和?
线程之间的eventfd无法正确传输数据。 我也不喜欢pipe道。 如何在线程之间正确地传输数据?
eventfd使用由提供给eventfd()的值开始的内核维护的计数器。 这个计数器是通过write()函数递增的,所以如果你创建的eventfd初始值为1,然后写入()2,那么你读取的值就是3.如果你再写入()5 ,read()的值将是8等等。
事件驱动模式中的线程通常使用eventfd,但您需要使用队列或其他容器来传递实际值,或者检出signalfd(),它可以用来通过sigqueue()来调用附加到信号的数据。