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

标签 c unix named-pipes

我正在做一些实验来了解命名管道。据我了解,操作系统将阻止写入命名管道的程序,直到另一个程序从命名管道读取为止。所以我写了两个程序,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

最佳答案

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

这种理解是不正确的。 write 不会阻塞,除非管道/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 调用就会开始失败。

关于c - 为什么在没有人阅读后继续写入命名管道?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34621757/

相关文章:

c - 如何在此函数中返回2个结果

regex - 使用 perl oneliner 重命名匹配文件时出错

unix - 如何在命令行上对差异进行着色

ruby-on-rails - 我需要在所有目标机器(Capistrano)上安装公钥吗?

windows - 命名管道高效异步设计

javascript - 通过命名管道在 bash 和 JavaScript 之间传递消息

windows - 将 FFMPEG 的输出重定向到 Windows 上的多个命名管道

c - 我的 GCD 算法有什么问题?

c - 如何区分两位数(65)和字符 ('a' )?

c - C 中的链表示例