unlink()后从FIFO读取

Naf*_*aly 5 c ipc fifo

我创建了一个FIFO,写入它并取消链接.令我惊讶的是,我能够在取消链接后从fifo读取数据,为什么会这样?

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

#define MAX_BUF 256
int main()
{
    int fd;
    char * myfifo = "/tmp/myfifo";

    /* create the FIFO (named pipe) */
    mkfifo(myfifo, 0666);

    int pid = fork();
    if (pid != 0)
    {
        /* write "Hi" to the FIFO */
        fd = open(myfifo, O_WRONLY);
        write(fd, "Hi", sizeof("Hi"));
        close(fd);

        /* remove the FIFO */
        unlink(myfifo);
    }
    else 
    {
        wait(NULL);
        char buf[MAX_BUF];

        /* open, read, and display the message from the FIFO */
        fd = open(myfifo, O_RDONLY);
        read(fd, buf, MAX_BUF);
        printf("Received: %s\n", buf);
        close(fd);

        return 0;
    }


    return 0;
}
Run Code Online (Sandbox Code Playgroud)

Fil*_*ves 1

除非您将O_NONBLOCK标志传递给open(2),否则打开 FIFO 会阻塞,直到另一端打开。从man 7 fifo

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

进程可以以非阻塞模式打开 FIFO。在这种情况下,即使尚未有人在写入端打开,以只读方式打开也会成功,而仅以写入方式打开将因 ENXIO(没有此类设备或地址)而失败,除非另一端已打开。

也就是说,您的父/子进程在打开 FIFO 时隐式同步。所以当父进程调用 时unlink(2),子进程早就打开了 FIFO。因此,子进程总是会在父进程调用它之前找到 FIFO 对象并打开它unlink(2)

关于 的注释unlink(2)unlink(2)只是从文件系统中删除文件名;只要至少有一个进程打开该文件(本例中为 FIFO),底层对象就会持续存在。只有在该进程终止或关闭文件描述符后,操作系统才会释放相关资源。FWIW,这与这个问题的范围无关,但似乎值得注意。

其他一些(不相关的)评论:

  • 不要叫wait(2)孩子。它将返回一个错误(您可以立即忽略该错误),因为子进程没有分叉任何进程。
  • mkfifo(3)fork(2)open(2)read(2)write(2)close(2)unlink(2)可以失败并返回-1。您应该优雅地处理可能的错误,而不是忽略它们。这些玩具程序的常见策略是打印一条描述性错误消息并perror(3)终止。
  • 如果您只想父子通信,请使用管道:它更容易设置,您不需要取消链接它,并且它不会在文件系统中公开(但您需要在pipe(2)分叉之前创建它,以便子进程可以访问它)。