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 在阻塞模式下打开时冻结的主要内容,如果未能解决你的问题,请参考以下文章

POSIX消息队列

解决chrome在ubuntu+root模式下打不开的问题

POSIX消息队列 - mq_send线程唤醒命令

2022-04-22iOS项目混编flutter,iOS真机debug模式下打不开flutter页面

Linux posix线程库总结

数据结构 - SynchronousQueue 线程通信阻塞队列