13

我使用 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;
}
4

2 回答 2

20

尝试"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没有传递O_NONBLOCKopen

$ strace -P /tmp/myFIFO ./a.out
open("/tmp/myFIFO", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
...

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

只读,没有O_NONBLOCK:open阻塞,直到另一个进程打开 FIFO 进行写入。这是使用fopenwith mode argument时的行为"r"

只写,没有O_NONBLOCK:open阻塞,直到另一个进程打开 FIFO 进行读取。这是使用fopenwith mode argument时的行为"w"

只读,带有O_NONBLOCK:open立即返回。

只写,with O_NONBLOCK:open返回错误并errno设置为,ENXIO除非另一个进程打开 FIFO 以供读取。

来自 W. Richard Stevens 的“UNIX 环境中的高级编程”的信息。

打开 FIFO进行读写

Linux 也可以在同一进程中打开一个 FIFO 进行读取和写入。Linux FIFO 手册页指出:

在 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 以外的操作系统上运行。

于 2012-07-24T19:19:02.027 回答
12

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

于 2011-12-14T16:19:01.190 回答