24

fcntlopenread、およびの The Open Group Web サイトで読んだことから、 がファイル記述子に設定されているかどうか、したがって、非ブロッキング I/O が記述子で使用されているかどうかは、 のプロパティである必要があるというwrite印象を受けました。O_NONBLOCK基になるファイルではなく、そのファイル記述子。ファイル記述子のプロパティであるということは、たとえば、ファイル記述子を複製するか、同じファイルに対して別の記述子を開く場合、一方にはブロッキング I/O を使用し、もう一方には非ブロッキング I/O を使用できることを意味します。

ただし、FIFO を試してみると、FIFO に対してブロッキング I/O 記述子と非ブロッキング I/O 記述子を同時に持つことはできないようです (したがって、O_NONBLOCK設定されているかどうかは、基になるファイル [FIFO] のプロパティです)。 ):

#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char **argv)
{
    int fds[2];
    if (pipe(fds) == -1) {
        fprintf(stderr, "`pipe` failed.\n");
        return EXIT_FAILURE;
    }

    int fd0_dup = dup(fds[0]);
    if (fd0_dup <= STDERR_FILENO) {
        fprintf(stderr, "Failed to duplicate the read end\n");
        return EXIT_FAILURE;
    }

    if (fds[0] == fd0_dup) {
        fprintf(stderr, "`fds[0]` should not equal `fd0_dup`.\n");
        return EXIT_FAILURE;
    }

    if ((fcntl(fds[0], F_GETFL) & O_NONBLOCK)) {
        fprintf(stderr, "`fds[0]` should not have `O_NONBLOCK` set.\n");
        return EXIT_FAILURE;
    }

    if (fcntl(fd0_dup, F_SETFL, fcntl(fd0_dup, F_GETFL) | O_NONBLOCK) == -1) {
        fprintf(stderr, "Failed to set `O_NONBLOCK` on `fd0_dup`\n");
        return EXIT_FAILURE;
    }

    if ((fcntl(fds[0], F_GETFL) & O_NONBLOCK)) {
        fprintf(stderr, "`fds[0]` should still have `O_NONBLOCK` unset.\n");
        return EXIT_FAILURE; // RETURNS HERE
    }

    char buf[1];
    if (read(fd0_dup, buf, 1) != -1) {
        fprintf(stderr, "Expected `read` on `fd0_dup` to fail immediately\n");
        return EXIT_FAILURE;
    }
    else if (errno != EAGAIN) {
        fprintf(stderr, "Expected `errno` to be `EAGAIN`\n");
        return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}

これは私に考えさせます:ノンブロッキングI/O記述子とブロッキングI/O記述子を同じファイルに持つことは可能ですか?もしそうなら、それはファイルのタイプ(通常のファイル、FIFO、ブロック特殊ファイル)に依存しますか? 、キャラクタースペシャルファイル、ソケットなど)?

4

1 に答える 1

36

O_NONBLOCK は、開いているファイルの説明のプロパティであり、ファイル記述子や基になるファイルのプロパティではありません。

はい、同じファイルに対して別々のファイル記述子を開くことができます.1つはブロックされ、もう1つは非ブロックです。

mkfifo()FIFO ( を使用して作成) とパイプ ( を使用して作成)を区別する必要がありますpipe()

ブロック状態は「開いているファイルの説明」のプロパティですが、最も単純なケースでは、ファイル記述子と開いているファイルの説明の間に 1 対 1 のマッピングがあることに注意してください。関数呼び出しはopen()、新しいオープン ファイル記述と、オープン ファイル記述を参照する新しいファイル記述子を作成します。

を使用するdup()と、1 つの開いているファイルの説明を共有する 2 つのファイル記述子があり、プロパティは開いているファイルの説明に属します。の説明にfcntl()よると、F_SETFL は、ファイル記述子に関連付けられたオープン ファイルの説明に影響を与えます。lseek()ファイル記述子に関連付けられた開いているファイル記述のファイル位置を調整することに注意してください。そのため、元のファイル記述子から複製された他のファイル記述子に影響します。

コードからエラー処理を削除して削減すると、次のようになります。

int fds[2];
pipe(fds);
int fd0_dup = dup(fds[0]);
fcntl(fd0_dup, F_SETFL, fcntl(fd0_dup, F_GETFL) | O_NONBLOCK);

現在、 と の両方fd0_dupfds[0]同じ開いているファイルの説明を参照しているため ( のためdup())、fcntl()操作は両方のファイル記述子に影響を与えました。

if ((fcntl(fds[0], F_GETFL) & O_NONBLOCK)) { ... }

したがって、ここで観察された動作は POSIX によって要求されます。

于 2010-05-22T21:58:27.863 に答える