c++ - 为什么我的程序在打开 mkfifo-ed 管道时挂起?

标签 c++ c mkfifo

我使用 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+"(请参阅 this question for the differences 的答案)。

此程序将正确写入 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_NONBLOCK传递给open:

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

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

只读,没有O_NONBLOCK:open 阻塞,直到另一个进程打开FIFO 进行写入。这是使用带有模式参数 "r"fopen 时的行为。

只写,没有O_NONBLOCK:open 阻塞,直到另一个进程打开FIFO 进行读取。这是使用带有模式参数 "w"fopen 时的行为。

只读,O_NONBLOCK:打开立即返回。

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

<支持> 来自 W. Richard Stevens 的“Advanced Programming in the UNIX Environment”的信息。

打开一个 FIFO 进行读

Linux 也可以在同一个进程中打开一个 FIFO 进行读取和写入。 Linux FIFO man page状态:

Under Linux, opening a FIFO for read and write will succeed both in blocking and nonblocking mode. POSIX leaves this behavior undefined. This can be used to open a FIFO for writing while there are no readers available. A process that uses both ends of the connection in order to communicate with itself should be very careful to avoid deadlocks.

这是一个从同一个 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 以外的操作系统。

关于c++ - 为什么我的程序在打开 mkfifo-ed 管道时挂起?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34676410/

相关文章:

c++ - 长除法余数的模式匹配

c++ - 无法从继承类调用 assert()

c - 将C代码转换为汇编语言

linux - 在 linux/bash 中使用非阻塞 FIFO 流式传输视频

bash - 在 shell 脚本中使用 mkfifo

c++ - double 值以整数形式打印

c++ - d3d->CreateDevice 中的 D3DERR_INVALIDCALL 导致 Allegro 5 D3D 程序启动时窗口闪烁

c - 在 BST 中插入节点的问题(迭代方法)

python - 使用 ctypes 包装具有依赖项的编译库

c - 在 C 中实现流水线。最好的方法是什么?