Cygwin - 阻止打开命名的 fifo 会导致另一个线程阻止打开常规文件

Posted

技术标签:

【中文标题】Cygwin - 阻止打开命名的 fifo 会导致另一个线程阻止打开常规文件【英文标题】:Cygwin - Blocking on opening a named fifo causes another thread to block on opening a regular file 【发布时间】:2020-09-01 15:50:37 【问题描述】:

在 Cygwin 中阻止打开命名管道会导致另一个线程在尝试打开任何文件(包括简单文本文件)时挂起。下面的代码重现了 cygwin 3.1.6(0.340/5/3) 上的问题,并且在 RHEL 7 上工作正常(不挂起)。

#include <unistd.h>
#include <limits.h>
#include <stdio.h>
#include <thread>
#include <sys/stat.h>
#include <fcntl.h>

void openFile() 
    int fd;

    printf("inside new thread\n");
    sleep(10); // Ensure main thread reaches call to open()
    
    printf("opening a simple file\n");
    if((fd = open("simpleFile", 0600)) == -1)  // simpleFile is a simple text file in the filesystem
        printf("failed opening a simple file\n");
    
    printf("simple file opened successfully\n");
    close(fd);
    printf("simple file closed\n");


int main(int argc, char *argv[]) 
    int fd;
    char readBuffer[PIPE_BUF];
    
    printf("creating named pipe\n");
    if (mkfifo("namedPipe", 0600)) 
        printf("creating named pipe failed\n");
    
    
    printf("creating thread\n");
    std::thread pipeCreator = std::thread(openFile);
    
    printf("opening named pipe for read\n");
    fd = open("namedPipe", O_RDONLY); // Block will only release when we echo something into namedPipe
    printf("reading from named pipe\n");
    if (read(fd, readBuffer, PIPE_BUF) == -1) 
        printf("error reading from pipe\n");
    
    printf("read successfully from named pipe\n");
    
    pipeCreator.join();
    
    return 0;

运行此打印:

creating named pipe
creating thread
opening named pipe for read
inside new thread
opening a simple file

然后阻塞,直到打开 namedPipe 的另一侧。 一旦被释放,它就会写入其余的打印:

reading from named pipe
simple file opened successfully
read successfully from named pipe
simple file closed

在 RHEL 上,这会打印出预期的结果:

creating named pipe
creating thread
opening named pipe for read
inside new thread
opening a simple file
simple file opened successfully
simple file closed

只有这样,主线程才会挂起,直到某些内容回显到 namedPipe。

我们正在研究一种不会阻塞的解决方法,但这涉及到忙于等待,这不是很好。 谁能解释这种行为?

【问题讨论】:

我只能确认您的发现。我在 cygwin 中尝试使用 g++ 9.3.0 和 clang++ 8.0.1,它对我的​​作用相同。我试图查看strace -f 是否给出了任何提示,但除了挂在open() 上之外,我没有看到任何其他信息。 :-/ 【参考方案1】:

在 Cygwin 上,open 系统调用会在整个系统调用期间锁定文件描述符表。这意味着所有open 系统调用基本上都是顺序化的。

syscalls.cc/open():

extern "C" int
open (const char *unix_path, int flags, ...)

      . . .
      cygheap_fdnew fd;  // <-- here

还有cygheap.h:

class cygheap_fdnew : public cygheap_fdmanip

 public:
  cygheap_fdnew (int seed_fd = -1, bool lockit = true)
  
    if (lockit)
      cygheap->fdtab.lock ();  // <-- here
    . . .

我认为解决这个问题没有简单的方法,但我想至少在 fifo 的情况下创建描述符后应该可以解锁 fd 表(请参阅fhandler_fifo),因为fifo 阻塞open。您可以在cygwin-developers 上进一步讨论。

【讨论】:

我们当前的解决方法是使用 O_NONBLOCK 标志打开并休眠,而读取的结果是读取 0 字节

以上是关于Cygwin - 阻止打开命名的 fifo 会导致另一个线程阻止打开常规文件的主要内容,如果未能解决你的问题,请参考以下文章

在 Cygwin 中创建文件夹导致权限顺序错误,无法打开文件

IPC - 命名管道(fifo)- 使用

IPC - 命名管道(fifo)- 使用

IPC - 命名管道(fifo)- 使用

IPC - 命名管道(fifo)- 使用

从命名管道并发选择