4

私はepollの使い方を学んでいて、次の例を書きました

#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/epoll.h>
#include <unistd.h>

int main() {
    int epfd;
    struct epoll_event ev;
    struct epoll_event ret;
    char buf[200];
    int n,k,t;

    epfd = epoll_create(100);
    assert(0 ==
            fcntl(0, F_SETFL, fcntl(0, F_GETFL) | O_NONBLOCK)
          );

    ev.data.fd = 0;
    ev.events = EPOLLIN  | EPOLLET;

    if(epoll_ctl(epfd, EPOLL_CTL_ADD, 0, &ev) != 0)
        perror("epoll_ctl");


    while((n = epoll_wait(epfd, &ret, 1, -1)) > 0) {
        printf("tick!\n");

        if(ret.data.fd == 0) {
            k=0;
            while((t=read(0, buf, 100)) > 0) {
                k+=t;
            }   

            if(k == 0) {
                close(0);
                printf("stdin done\n");
            }
        }   
    }

    perror("epoll");
    return 0;
}

ターミナルで実行しようとすると、fds 0、1、および 2 がすべて同じ開いているファイルを指しているため、適切に動作しません。そのため、close(0) は epoll セットから stdin を削除しません。「cat | ./a.out」を実行することで、これを回避できます。汚いトリックですが、名前付きパイプまたはソケットを使用して小さな例を設定すると、より複雑になります。

これで、すべてが機能し、ファイルは epoll セットから削除されますが、空のセット上にあるため、次の epoll_wait 呼び出しは永久にブロックされます! したがって、epoll ファイル記述子 (epfd) が空の epoll セットであるかどうかを検出する必要があります。

どうすればこれを回避できますか? (一般的な方法で、stdin が完了したときに exit を呼び出すだけではありません) ありがとう!

4

2 に答える 2

0

追加したものをすべて削除すると、epoll セットは空になります。私の知る限り、ファイル記述子が存在するかどうかを調べるために epoll セットをイントロスペクトすることはできません。したがって、アーミンの回答で概説されているように、epoll セットがいつ空になるかを判断するのはあなた次第です。

プログラムに期待することを説明していないので、 stdin が閉じられたときにプログラムが終了することを期待していると推測します。これを行うと、close(0)ファイル記述子 0 が epoll セットから削除される可能性があるためです。ただし、リストされているコードには欠陥があります。ファイル記述子を含まない epoll セットを待機し続けると (自動的に削除されたか、 を使用して削除されたかに関係なくEPOLL_CTL_DEL)、 はepoll_wait永久に待機します。

次のコードはこれをうまく示しています。

#include <errno.h>
#include <stdio.h>
#include <sys/epoll.h>

int main() {
    int epfd;
    int n;
    struct epoll_event ret;

    epfd = epoll_create(100);

    while((n = epoll_wait(epfd, &ret, 1, -1)) > 0) {
        /* Never gets here. */
        printf("tick!\n");
    }

    return 0;
}

epoll セットにはファイル記述子が含まれていないため、epoll_wait永遠に待機します。プログラムで stdin に接続されたファイルがあり、プログラム内の他のファイル記述子が stdin に接続されていなかった場合、close(0)はセットから fd 0 を削除し、epoll セットは空になり、次はepoll_wait永久に待機します。

一般に、epoll セット内のファイル記述子は自分で管理closeし、セットからファイル記述子を自動的に削除する呼び出しに依存しません。close(0). _

epoll_wait また、プログラムの構造を の後に変更することをお勧めしますread。これにより、 への最初の呼び出しの前に stdin に到着した可能性のあるデータを確実に取得できますepoll_wait

また、次のようなコードにも注意してください。

k=0;
while((t=read(0, buf, 100)) > 0) {
    k+=t;
}   
if(k == 0) {
    close(0);
    printf("stdin done\n");
}

readループ内で が連続して 100 を返し、その後に一部のデータとファイルの終わりを示す 0 が続くと仮定すると、close(0)は呼び出されません。プログラムはループし、 で再び永久に待機しますepoll_waitread特にファイルの終わりとエラーについて、それぞれの結果を確認することをお勧めします。

于 2013-04-26T07:05:12.297 に答える