我创建了一个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)
除非您将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)
分叉之前创建它,以便子进程可以访问它)。