POSIX FIFO 在阻塞模式下打开时冻结
Posted
技术标签:
【中文标题】POSIX FIFO 在阻塞模式下打开时冻结【英文标题】:POSIX FIFO freezes when opened in blocking mode 【发布时间】:2020-05-28 23:15:06 【问题描述】:默认情况下,POSIX FIFO 在阻塞模式下打开。我的问题是,当我以阻塞模式打开它时,它只会冻结(阻塞)而没有其他任何反应。
最初我用 RDWR 标志打开了两边,我没有遇到任何问题,因为 RDWR 使它成为非阻塞的,因为“在 Linux 下,打开 FIFO 进行读写将在阻塞和非阻塞模式下都成功”(https://linux.die.net/man/7/fifo)。但是在非阻塞模式下我有时会丢失记录,所以我需要在阻塞模式下打开它。
我是这样称呼 mkfifo 的:
int64_t fifo_setup(char * fifo_name)
if (mkfifo(fifo_name, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH) == -1)
perror("mkfifo");
exit(EXIT_FAILURE);
return 0;
我最初的打开电话:
int64_t fifo_open(char * fifo_name, int64_t read_write)
int c;
if (read_write == 1)
c = open(fifo_name, O_RDWR);
if (read_write == 2)
c = open(fifo_name, O_RDWR);
perror("open");
return (c);
然后我改成:
int64_t fifo_open(char * fifo_name, int64_t read_write)
int c;
if (read_write == 1)
c = open(fifo_name, O_WRONLY);
if (read_write == 2)
c = open(fifo_name, O_RDONLY);
perror("open");
return (c);
我的程序到达编写器线程的打开调用(这是对 C 的 NASM 调用):
Open_FIFO_Write:
lea rdi,[fifo_name]
mov rsi,1
call fifo_open wrt ..plt
mov [fifo_write_fd],rax
但随后 Putty 终端冻结(阻塞)并且没有其他任何事情发生。我从来没有到达打开阅读面的街区。具体来说,它会在上面的 fifo_open 代码中到达 perror("open") 之前阻塞:
根据https://www.man7.org/linux/man-pages/man7/fifo.7.html 的 Linux 手册页,“通常,打开 FIFO 块直到另一端也打开。”这很好,但我无法找到打开作者的代码,因为阅读器阻止了所有进一步的进展。这就像墨西哥的对峙。
当然一定有办法,但我的研究还没有找到。
感谢您对此的任何帮助。
【问题讨论】:
您是否尝试在一个进程中打开管道的两端?为什么?为什么在一个进程中使用管道?如果您打算将其传递给您fork
的子进程,为什么要使用命名管道而不是 pipe
系统调用创建的匿名管道?
使用匿名管道与命名管道相比有什么好处?我从来没有听说过 IPC 不能用于同一进程的线程之间进行通信,这就是我正在做的事情。我唯一的问题是当管道缓冲区填满时删除记录。
匿名管道比命名管道使用更少的资源。并且由于两端都是通过单个系统调用完全打开并返回的,因此您不必担心死锁情况(无论如何都不是那部分)。但是对于线程间通信,请考虑使用甚至 less 资源并且不必多次通过用户内核边界的东西。例如,一个循环队列全部在用户空间中实现。一定有无锁实现可供您使用。
【参考方案1】:
三个选项:
-
FIFO 本身不会在非阻塞模式下丢弃消息。如果您的代码正在丢弃消息,请修复您的代码以停止这样做,然后使用非阻塞模式。
以非阻塞模式打开 FIFO,然后在两端打开后,使用
fcntl
将其更改为阻塞模式。
使用单独的线程或进程打开 FIFO 的每一半。
【讨论】:
我会尝试 #2。两侧以单独的线程打开,但我没有通过阅读器一侧的打开。至于#1,如果以非阻塞模式打开管道并且管道缓冲区已满,那么我相信写入端会删除记录。这就是非阻塞 IPC 通常的工作方式。 1.如果您在缓冲区已满的情况下执行非阻塞写入,它将失败并显示EWOULDBLOCK
。如果您没有注意到这一点,则意味着您没有检查write
的结果,这始终是一个错误。 2. 不,他们不是。在您问题的代码中,两端都在同一个线程中打开。
感谢您的信息。作为一个小问题,我的代码中的两个 C 代码块是从不同的线程调用的——它们只是出现在同一个 C 文件中。以上是关于POSIX FIFO 在阻塞模式下打开时冻结的主要内容,如果未能解决你的问题,请参考以下文章