为什么我在打开一个使用mkfifo创建的管道时程序会挂起?

14

我使用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;
}
2个回答

25
尝试将"w"作为fopen的模式参数传递。 "rw"不是fopen的有效模式参数,即使它是有效的,您也可能不想在同一进程中同时读取和写入FIFO(尽管这是可能的,请参见下文)。
另外,正确的模式参数以便打开文件进行读写操作应该是"r+""w+"(请参阅此问题的答案以了解区别)。
此程序将正确地写入FIFO:
#include <stdio.h>
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没有向open传递O_NONBLOCK参数:
$ strace -P /tmp/myFIFO ./a.out
open("/tmp/myFIFO", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
...

关于如何打开FIFO的背景知识

只读,没有O_NONBLOCK:使用fopen并将模式参数设置为"r"时,open会阻塞,直到另一个进程打开FIFO进行写入。

只写,没有O_NONBLOCK:使用fopen并将模式参数设置为"w"时,open会阻塞,直到另一个进程打开FIFO进行读取。

只读,有O_NONBLOCKopen会立即返回。

只写,有O_NONBLOCK:除非另一个进程已经打开了FIFO进行读取,否则open会返回一个带有errno设置为ENXIO的错误。

摘自"UNIX环境高级编程" by W. Richard Stevens.

打开FIFO以进行读取和写入

在Linux中,对于同一进程而言,读写同一个FIFO也是可能的。Linux FIFO man page指出:

在Linux下,以读写方式打开FIFO在阻塞和非阻塞模式下都会成功。POSIX标准未定义此行为。这可以用于在没有读者时打开FIFO进行写入。使用连接的两端与自己通信的进程应该非常小心,以避免死锁。

以下是一个同时向同一个FIFO写入和读取的程序:

#include <stdio.h>
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以外的操作系统上无法正常工作。

13

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接