4

カーネルスペースとユーザースペースの間の単純なイベントを通知する方法としてeventfdを使用したいと思います。eventfdは信号を送る方法として使用され、実際のデータはioctlを使用して転送されます。これを実装する前に、eventfdがselect()でどのように動作するかを確認するための簡単なプログラムを作成しました。selectを使用してeventfdを待機している場合、別のスレッドで書き込みを行っても戻りません。私が書いたコードでは、書き込みスレッドはプログラムの開始から5秒間待機してから、eventfdに2回書き込みます。select()がこの書き込みの直後に読み取りスレッドに戻ることを期待しますが、これは起こりません。select()は、10秒のタイムアウト後にのみ戻り、ゼロを返します。この戻り値ゼロに関係なく、10秒後にeventfdを読み取ろうとすると、正しい値が得られます。

Ubuntu 12.04.1(3.2.0-29-generic-pae)i386を使用しています

なぜそうなのか、何か考えはありますか?select()が正常に機能していないように思われます。

PS:この質問はLinuxに似ています-eventfdをepollと一緒に動作させることはできません

他の誰かが同様の問題に直面していますか?

#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 に答える