我想使用 eventfd 作为在内核空间和用户空间之间发出简单事件信号的一种方式。eventfd 将用作一种信号方式,实际数据将使用 ioctl 传输。在继续实现它之前,我编写了一个简单的程序来查看 eventfd 与 select() 的行为。似乎如果您使用 select 等待 eventfd,当您在单独的线程中写入它时它不会返回。在我编写的代码中,写入线程从程序启动开始等待 5 秒,然后再写入 eventfd 两次。我希望 select() 在写入后立即在读取线程中返回,但这不会发生。select() 仅在 10 秒超时后返回并返回零。不管这个返回零,当我在 10 秒后尝试读取 eventfd 时,我得到了正确的值。
我使用 Ubuntu 12.04.1 (3.2.0-29-generic-pae) i386
知道为什么会这样吗?在我看来, select() 没有按应有的方式工作。
PS:这个问题类似于linux - Can't get eventfd to work with epoll together
还有其他人面临类似的问题吗?
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h> //Definition of uint64_t
#include <pthread.h> //One thread writes to fd, other waits on it and then reads it
#include <time.h> //Writing thread uses delay before writing
#include <sys/eventfd.h>
int efd; //Event file descriptor
void * writing_thread_func() {
uint64_t eftd_ctr = 34;
ssize_t s;
printf("\n%s: now running...",__func__);
printf("\n%s: now sleeping for 5 seconds...",__func__);
fflush(stdout); //must call fflush before sleeping to ensure previous printf() is executed
sleep(5);
printf("\n%s: Writing %lld to eventfd...",__func__,eftd_ctr);
s = write(efd, &eftd_ctr, sizeof(uint64_t));
if (s != sizeof(uint64_t)) {
printf("\n%s: eventfd writing error. Exiting...",__func__);
exit(EXIT_FAILURE);
}
eftd_ctr = 99;
printf("\n%s: Writing %lld to eventfd...",__func__,eftd_ctr);
s = write(efd, &eftd_ctr, sizeof(uint64_t));
if (s != sizeof(uint64_t)) {
printf("\n%s: eventfd writing error. Exiting...",__func__);
exit(EXIT_FAILURE);
}
printf("\n%s: thread exiting...",__func__);
pthread_exit(0);
}
void * reading_thread_func() {
ssize_t s;
uint64_t eftd_ctr;
int retval; //for select()
fd_set rfds; //for select()
struct timeval tv; //for select()
printf("\n%s: now running...",__func__);
printf("\n%s: now waiting on select()...",__func__);
//Watch efd
FD_ZERO(&rfds);
FD_SET(efd, &rfds);
//Wait up to 10 seconds
tv.tv_sec = 10;
tv.tv_usec = 0;
retval = select(1, &rfds, NULL, NULL, &tv);
if (retval == -1){
printf("\n%s: select() error. Exiting...",__func__);
exit(EXIT_FAILURE);
} else if (retval > 0) {
printf("\n%s: select() says data is available now. Exiting...",__func__);
printf("\n%s: returned from select(), now executing read()...",__func__);
s = read(efd, &eftd_ctr, sizeof(uint64_t));
if (s != sizeof(uint64_t)){
printf("\n%s: eventfd read error. Exiting...",__func__);
exit(EXIT_FAILURE);
}
printf("\n%s: Returned from read(), value read = %lld",__func__, eftd_ctr);
} else if (retval == 0) {
printf("\n%s: select() says that no data was available even after 10 seconds...",__func__);
printf("\n%s: but lets try reading efd count anyway...",__func__);
s = read(efd, &eftd_ctr, sizeof(uint64_t));
if (s != sizeof(uint64_t)){
printf("\n%s: eventfd read error. Exiting...",__func__);
exit(EXIT_FAILURE);
}
printf("\n%s: Returned from read(), value read = %lld",__func__, eftd_ctr);
exit(EXIT_FAILURE);
}
printf("\n%s: thread exiting...",__func__);
pthread_exit(0);
}
int main() {
pthread_t writing_thread_var, reading_thread_var;
//Create eventfd
efd = eventfd(0,0);
if (efd == -1){
printf("\n%s: Unable to create eventfd! Exiting...",__func__);
exit(EXIT_FAILURE);
}
printf("\n%s: eventfd created. value = %d. Spawning threads...",__func__,efd);
//Create threads
pthread_create(&writing_thread_var, NULL, writing_thread_func, NULL);
pthread_create(&reading_thread_var, NULL, reading_thread_func, NULL);
//Wait for threads to terminate
pthread_join(writing_thread_var, NULL);
pthread_join(reading_thread_var, NULL);
printf("\n%s: closing eventfd. Exiting...",__func__);
close(efd);
exit(EXIT_SUCCESS);
}