4

我想使用 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);
}
4

1 回答 1

3

所以这是一个愚蠢的错误:

我变了:

retval = select(1, &rfds, NULL, NULL, &tv);

到:

retval = select(efd+1, &rfds, NULL, NULL, &tv);

它奏效了。

再次感谢@Steve-o

于 2012-11-29T14:42:50.270 回答