Cygwin-打开命名的fifo时导致阻塞,导致另一个线程在打开常规文件时阻塞

问题描述

在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上,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),因为{{3 }}在open上阻止。您可以在fifo上进一步讨论。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...