打开mkfifo-ed管道时为什么我的程序会挂起?
我使用mkfifo来创建一个命名管道。 然后我使用以下程序打开它。 但是,该程序挂在“fopen”行。 这里有什么问题吗?
int main(int argc, char** argv) { char* line = "hello, world!"; FILE* fp = fopen("/tmp/myFIFO", "rw"); fprintf(fp, line); fclose(fp); return 0; }
尝试将"w"
作为模式传递给fopen。 "rw"
不是fopen
的有效模式参数,即使它是,你可能不希望在同一个进程中同时读取和写入FIFO(尽管有可能,见下文)。
另外,打开文件进行读写的正确模式参数是"r+"
或"w+"
( 有关差异,请参阅此问题的答案)。
该程序将正确写入FIFO:
#include int main(int argc, char** argv) { FILE* fp = fopen("/tmp/myFIFO", "w"); fprintf(fp, "Hello, world!\n"); fclose(fp); return 0; }
请注意,上述程序中的fopen
将一直阻塞,直到FIFO打开进行读取。 当它阻塞时,在另一个终端运行:
$ cat /tmp/myFIFO Hello, world! $
它阻塞的原因是因为fopen
没有通过O_NONBLOCK
open
:
$ strace -P /tmp/myFIFO ./a.out open("/tmp/myFIFO", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3 ...
关于如何打开FIFO的一些背景知识
只读,没有O_NONBLOCK
: open
块,直到另一个进程打开FIFO进行写入。 这是使用fopen
与模式参数"r"
时的行为。
只写,没有O_NONBLOCK
: open
块,直到另一个进程打开FIFO进行读取。 这是使用fopen
与模式参数"w"
时的行为。
只读,使用O_NONBLOCK
: open
立即返回。
只写,使用O_NONBLOCK
: open
返回错误,并将errno
设置为ENXIO
除非另一个进程打开FIFO进行读取。
来自W. Richard Stevens的“UNIX环境中的高级编程”的信息。
打开FIFO进行读写
Linux也可以在同一个进程中打开FIFO进行读写。 Linux FIFO手册页指出:
在Linux下,打开FIFO进行读写将在阻塞和非阻塞模式下成功。 POSIX将此行为保留为未定义。 这可用于打开FIFO进行写入,而没有可用的读取器。 使用连接的两端以便与自身通信的进程应该非常小心以避免死锁。
这是一个写入和读取同一FIFO的程序:
#include int main(int argc, const char *argv[]) { char buf[100] = {0}; FILE* fp = fopen("/tmp/myFIFO", "r+"); fprintf(fp, "Hello, world!\n"); fgets(buf, sizeof(buf), fp); printf("%s", buf); fclose(fp); return 0; }
它不会阻塞,并立即返回:
$ gcc fifo.c && ./a.out Hello, world!
请注意,这不是可移植的,并且可能无法在除Linux之外的操作系统上运行。
该过程将阻塞,直到管道的另一端打开。