macOSのFIFOから選択(2)

macOSのFIFOから選択(2)

Linuxでは、含まれているプログラムは次のselect場所から返され、終了します。

$ gcc -Wall -Wextra select_test.c -o select_test
$ ./select_test
reading from read end
closing write end
first read returned 0
second read returned 0
selecting with read fd in fdset
select returned

OS Xではselect永久にブロックされ、プログラムは決して終了しません。 Linuxは期待どおりに機能し、POSIXのマニュアルページの次の選択セクションに従うようです。

O_NONBLOCK がクリアされた入力関数への呼び出しがブロックされない場合、記述子は関数がデータを正常に送信したかどうかにかかわらず読み取る準備ができたと見なされます。 (関数は、データ、ファイルの終わりの表示、またはブロックされたことを示すエラーを返すことがあります。それぞれの場合、記述子を読み取る準備ができたと見なす必要があります。)

fifoの読み取り側のread(2)は常にを返すので、EOF私の読み取りによると、常に選択によって準備されたと見なされるべきです。

macOSの動作はよく知られているか予想されますか?この例では、行動の違いに寄与する他の要因がありますか?

readこれらの呼び出しを削除すると、macOSがselect置き換えられます。この実験とは異なる実験では、ファイルからEOFを読み取ると、後で呼び出しても準備ができているとマークされなくなるselectことを示しているようです。

サンプルプログラム

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

#define FILENAME "select_test_tmp.fifo"

int main() 
{
    pid_t pid;
    int r_fd, w_fd;
    unsigned char buffer[10];
    fd_set readfds;

    mkfifo(FILENAME, S_IRWXU);

    pid = fork();
    if (pid == -1) 
    {
        perror("fork");
        exit(1);
    }

    if (pid == 0) 
    {
        w_fd = open(FILENAME, O_WRONLY);

        if (w_fd == -1) 
        {
            perror("open");
            exit(1);
        }

        printf("closing write end\n");
        close(w_fd);
        exit(0);
    }

    r_fd = open(FILENAME, O_RDONLY);
    if (r_fd == -1) 
    {
        perror("open");
        exit(1);
    }

    printf("reading from read end\n");

    if (read(r_fd, &buffer, 10) == 0) 
    {
        printf("first read returned 0\n");
    } 
    else 
    {
        printf("first read returned non-zero\n");
    }

    if (read(r_fd, &buffer, 10) == 0) 
    {
        printf("second read returned 0\n");
    } 
    else 
    {
        printf("second read returned non-zero\n");
    }

    FD_ZERO(&readfds);
    FD_SET(r_fd, &readfds);

    printf("selecting with read fd in fdset\n");
    if (select(r_fd + 1, &readfds, NULL, NULL, NULL) == -1) 
    {
        perror("select");
        exit(1);
    }

    printf("select returned\n");
    unlink(FILENAME);
    exit(0);
}

ベストアンサー1

Macintoshでは、この関数はパイプをソケットと同じように扱いますread。この動作は、readファイルにアクセスしようselect_test_tmp.fifoとし、無料の入力がある限りブロックされるために発生します。デフォルトでは、EOFは各書き込み操作の後にパイプに書き込まれます。

これを確認する1つの方法は、cat select_test_tmp.fifoコマンドラインから実行することです。最初に終了しない限り、返す前に入力を受け取るのを待ちます。

おすすめ記事