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)
创建它,以便孩子可以访问它)。