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

wat*_*pet 1 c unix named-pipes

我正在做一些实验来了解命名管道。我的理解是操作系统将阻止写入命名管道的程序,直到另一个程序从命名管道读取。所以我写了两个程序,startloopreadbyte. startloop创建一个 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;
}
Run Code Online (Sandbox Code Playgroud)

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;
}
Run Code Online (Sandbox Code Playgroud)

readbyte 在“fifo”上运行时按预期打印数字:

hostname:dir username$ ./readbyte fifo 
65
Run Code Online (Sandbox Code Playgroud)

正如我所料,loopstart在我使用readbyte. 然而,当它被解除阻塞时,它会多次写入“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
Run Code Online (Sandbox Code Playgroud)

kay*_*lum 5

“据我所知,操作系统将阻止写入命名管道的程序,直到另一个程序从命名管道读取。”

这种理解是不正确的。write除非管道/FIFO 已满,否则不会阻塞。从管道手册

管道的容量有限。如果管道已满,则 write(2) 将阻塞或失败,具体取决于是否设置了 O_NONBLOCK 标志(见下文)。

至于为什么第一个write似乎会阻止 - 它实际上没有。就是open那个块。从先进先出手册

FIFO 必须在两端(读和写)都打开,然后才能传递数据。通常,打开 FIFO 会阻塞,直到另一端也打开。

更新:实际上,第一个write. 但可能还有更多解释。一旦readbyte程序关闭了先进先出,后续write调用应该开始失败。