为什么在没有人阅读后继续写入命名管道?

Why does writing to a named pipe continue after no one is reading?

我正在做一些实验来了解命名管道。据我了解,OS 将阻止写入命名管道的程序,直到另一个程序从命名管道读取为止。所以我写了两个程序,startloopreadbytestartloop 创建一个 fifo 并在客户端每次读取时不断写入它 (readbyte):

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

int main(int argc, char *argv[]) {
    const char num = 123;
    mkfifo("fifo", S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
    int fd = open("fifo", O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
    while (1) {
        printf("loop_start\n");
        write(fd, &num, sizeof(num));
    }
    close(fd);
    return 0;
}

readbyte 当运行:

时从fifo中读取一个字节
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>

int main(int argc, char *argv[]) {
    char num;
    int fd;
    if ((fd = open(argv[1], O_RDONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1) {
        perror("Cannot open input file\n"); exit(1);
    }

    read(fd, &num, sizeof(num));
    printf("%d\n", num);
    close(fd);
    return 0;
}

readbyte 在 "fifo":

上 运行 时按预期打印数字
hostname:dir username$ ./readbyte fifo 
65

如我所料,在我使用 readbyte 从 fifo 读取之前,loopstart 不会打印任何内容。但是,当它解除阻塞时,它会多次写入 "fifo" 而不是立即被挂起。这是为什么?

hostname:dir username$ ./startloop
loop_start
loop_start
loop_start
loop_start
loop_start
loop_start
loop_start
loop_start
loop_start
loop_start
loop_start
loop_start
loop_start
loop_start
loop_start
loop_start
loop_start
loop_start
loop_start
loop_start

测试写入结果

 while (1) {
        printf("loop_start\n");
     int ret =  write(fd, &num, sizeof(num));
     if(ret == -1)
     {
        perror("error writing to fifo");
        exit(1);
     }
    }

"It's my understanding that the OS will block a program that writes to a named pipe until another program reads from the named pipe."

这种理解是不正确的。 write 不会阻塞,除非 pipe/fifo 已满。来自 pipe manul:

A pipe has a limited capacity. If the pipe is full, then a write(2) will block or fail, depending on whether the O_NONBLOCK flag is set (see below).

至于为什么第一个 write 看起来是阻塞的——实际上并没有。阻塞的是 open。来自 fifo manaul:

The FIFO must be opened on both ends (reading and writing) before data can be passed. Normally, opening the FIFO blocks until the other end is opened also.

更新:实际上上述第一个 write 是正确的。但可能还有更多需要解释的地方。 readbyte 程序关闭 fifo 后,后续 write 调用应该开始失败。