Cygwin - 阻塞打开一个命名的 fifo 导致另一个线程阻塞打开一个常规文件
Cygwin - Blocking on opening a named fifo causes another thread to block on opening a regular file
在 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
系统调用在整个系统调用期间锁定文件描述符 table。这意味着所有 open
系统调用本质上都是顺序化的。
extern "C" int
open (const char *unix_path, int flags, ...)
{
. . .
cygheap_fdnew fd; // <-- here
class cygheap_fdnew : public cygheap_fdmanip
{
public:
cygheap_fdnew (int seed_fd = -1, bool lockit = true)
{
if (lockit)
cygheap->fdtab.lock (); // <-- here
. . .
我看不出解决这个问题的简单方法,但我想应该可以在创建描述符后解锁 fd table 至少在 fifo 的情况下(参见 fhandler_fifo
) , 因为 fifo blocks on open
. You can discuss this further on cygwin-developers.
在 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
系统调用在整个系统调用期间锁定文件描述符 table。这意味着所有 open
系统调用本质上都是顺序化的。
extern "C" int
open (const char *unix_path, int flags, ...)
{
. . .
cygheap_fdnew fd; // <-- here
class cygheap_fdnew : public cygheap_fdmanip
{
public:
cygheap_fdnew (int seed_fd = -1, bool lockit = true)
{
if (lockit)
cygheap->fdtab.lock (); // <-- here
. . .
我看不出解决这个问题的简单方法,但我想应该可以在创建描述符后解锁 fd table 至少在 fifo 的情况下(参见 fhandler_fifo
) , 因为 fifo blocks on open
. You can discuss this further on cygwin-developers.