1

親は、FIFO パイプを介して中止された子プロセスに文字を送信する SIGPIPE を受け取ります。select() 関数を使用して、これを回避しようとしています。添付のサンプル コードでは、select() は、パイプの相手側の子が終了した後でも OK を返します。
RedHat EL5 (Linux 2.6.18-194.32.1.el5)でテスト済みGNU C ライブラリ安定版リリース バージョン 2.5 助けていただければ幸いです。ありがとうございます。

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/stat.h>
#include <unistd.h>

static void sigpipe_fct();

main()
{
struct stat st;
int  i, fd_out, fd_in, child;
char buf[1024];
#define p_out "/tmp/pout"

    signal(SIGPIPE, sigpipe_fct);

    if (stat(p_out, &st) != 0)  {
        mknod(p_out, S_IFIFO, 0);
        chmod(p_out, 0666);
    }
    /* start receiving process */
    if ((child = fork()) == 0)  {
        if ((fd_in = open(p_out, O_RDONLY)) < 0)  {
            perror(p_out);
            exit(1);
        }
        while(1)  {
           i = read(fd_in, buf, sizeof(buf));
           fprintf(stderr, "child %d read %.*s\n", getpid(), i, buf);
           lseek(fd_in, 0, 0);
        }
    }
    else  {
        fprintf(stderr,
           "reading from %s - exec \"kill -9 %d\" to test\n", p_out, child);
        if ((fd_out = open(p_out, O_WRONLY + O_NDELAY)) < 0) { /*  output */
            perror(p_out);
            exit(1);
        }
        while(1)  {
            if (SelectChkWrite(fd_out) == fd_out)  {
                fprintf(stderr, "SelectChkWrite() success write abc\n");
                write(fd_out, "abc", 3);
            }
            else
                fprintf(stderr, "SelectChkWrite() failed\n");
            sleep(3);
        }
    }
}

static void sigpipe_fct()
{
    fprintf(stderr, "SIGPIPE received\n");
    exit(-1);
}

SelectChkWrite(ch)
int ch;
{
#include <sys/select.h>
fd_set  writefds;
int     i;

    FD_ZERO(&writefds);
    FD_SET (ch, &writefds);

    i = select(ch + 1, NULL, &writefds, NULL, NULL);

    if (i == -1)
        return(-1);
    else if (FD_ISSET(ch, &writefds))
        return(ch);
    else
        return(-1);
}
4

1 に答える 1

2

Linux のselect(3)マニュアル ページから:

O_NONBLOCK がクリアされた出力関数の呼び出しがブロックされない場合、関数がデータを正常に転送するかどうかにかかわらず、記述子は書き込みの準備ができていると見なされます。

パイプが閉じられるとブロックされないため、 によって「準備完了」と見なされselectます。

ところで、関数#include <sys/select.h> SelectChkWrite()あることは非常に悪い形です。

select()とはどちらもpoll()POSIX 標準select()ですが、 よりもはるかに古く、より制限されていpoll()ます。一般に、デフォルトで使用し、正当な理由がある場合にpoll()のみ使用することをお勧めします。(一例select()はこちらをご覧ください。)

于 2013-05-30T07:49:37.453 に答える