unlink()后从FIFO读取

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

#include  #include  #include  #include  #include  #include  #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; } 

除非将O_NONBLOCK标志传递给open(2) ,否则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)创建它,以便孩子可以访问它)。