打开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_NONBLOCKopen块,直到另一个进程打开FIFO进行写入。 这是使用fopen与模式参数"r"时的行为。

只写,没有O_NONBLOCKopen块,直到另一个进程打开FIFO进行读取。 这是使用fopen与模式参数"w"时的行为。

只读,使用O_NONBLOCKopen立即返回。

只写,使用O_NONBLOCKopen返回错误,并将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之外的操作系统上运行。

该过程将阻塞,直到管道的另一端打开。