O_NONBLOCK 是否被设置为文件描述符或底层文件的属性?

发布于 2024-09-02 23:04:04 字数 2352 浏览 4 评论 0原文

根据我在 The Open Group 网站上阅读的内容 fcntl打开阅读,以及write,我的印象是O_NONBLOCK< /code> 在文件描述符上设置,因此该描述符是否使用非阻塞 I/O 应该是该文件描述符的属性,而不是底层文件的属性。作为文件描述符的一项属性意味着,例如,如果我复制一个文件描述符或打开同一文件的另一个描述符,那么我可以对一个文件描述符使用阻塞 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、块特殊文件、字符特殊文件、套接字等)?

From what I have been reading on The Open Group website on fcntl, open, read, and write, I get the impression that whether O_NONBLOCK is set on a file descriptor, and hence whether non-blocking I/O is used with the descriptor, should be a property of that file descriptor rather than the underlying file. Being a property of the file descriptor means, for example, that if I duplicate a file descriptor or open another descriptor to the same file, then I can use blocking I/O with one and non-blocking I/O with the other.

Experimenting with a FIFO, however, it appears that it is not possible to have a blocking I/O descriptor and non-blocking I/O descriptor to the FIFO simultaneously (so whether O_NONBLOCK is set is a property of the underlying file [the 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;
}

This leaves me thinking: is it ever possible to have a non-blocking I/O descriptor and blocking I/O descriptor to the same file and if so, does it depend on the type of file (regular file, FIFO, block special file, character special file, socket, etc.)?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

偷得浮生 2024-09-09 23:04:04

O_NONBLOCK 是打开文件描述的属性,而不是文件描述符的属性,也不是底层文件的属性。

是的,您可以为同一个文件打开不同的文件描述符,其中一个是阻塞的,另一个是非阻塞的。

您需要区分 FIFO(使用 mkfifo() 创建)和一个管道(使用 pipe()< 创建/代码>)。

请注意,阻塞状态是“打开文件描述”的属性,但在最简单的情况下,文件描述符和打开文件描述之间存在一对一的映射。 open() 函数调用创建一个新的打开文件描述和引用打开文件描述的新文件描述符。

当您使用 dup() 时,您有两个文件描述符共享一个打开的文件描述,并且属性属于打开的文件描述。 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 所要求的。

O_NONBLOCK is a property of the open file description, not of the file descriptor, nor of the underlying file.

Yes, you could have separate file descriptors open for the same file, one of which is blocking and the other of which is non-blocking.

You need to distinguish between a FIFO (created using mkfifo()) and a pipe (created using pipe()).

Note that the blocking status is a property of the 'open file description', but in the simplest cases, there is a one-to-one mapping between file descriptors and open file descriptions. The open() function call creates a new open file description and a new file descriptor that refers to the open file description.

When you use dup(), you have two file descriptors sharing one open file description, and the properties belong to the open file description. The description of fcntl() says that F_SETFL affects the open file description associated with the file descriptor. Note that lseek() adjusts the file position of the open file description associated with the file descriptor - so it affects other file descriptors duplicated from the original one.

Removing the error handling from your code to reduce it, you have:

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

Now both fd0_dup and fds[0] refer to the same open file description (because of the dup()), so the fcntl() operation affected both file descriptors.

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

Hence the observed behaviour here is required by POSIX.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文