为啥只读打开命名管道块?
Posted
技术标签:
【中文标题】为啥只读打开命名管道块?【英文标题】:Why does a read-only open of a named pipe block?为什么只读打开命名管道块? 【发布时间】:2011-08-12 13:00:31 【问题描述】:在使用 Python 处理各种风格的 UNIX(Linux、FreeBSD 和 MacOS X)下的命名管道 (FIFO) 时,我注意到了一些奇怪的地方。第一个,也许是最烦人的是尝试打开一个空/空闲 FIFO 只读将阻塞(除非我使用 os.O_NONBLOCK
和较低级别的 os.open()
调用)。但是,如果我打开它进行读/写,那么我不会被阻塞。
例子:
f = open('./myfifo', 'r') # Blocks unless data is already in the pipe
f = os.open('./myfifo', os.O_RDONLY) # ditto
# Contrast to:
f = open('./myfifo', 'w+') # does NOT block
f = os.open('./myfifo', os.O_RDWR) # ditto
f = os.open('./myfifo', os.O_RDONLY|os.O_NONBLOCK) # ditto
我只是好奇为什么。为什么 open 调用阻塞而不是一些后续的读取操作?
我还注意到,非阻塞文件描述符在 Python 中会表现出不同的行为。在我使用os.open()
和os.O_NONBLOCK
进行初始打开操作的情况下,如果文件描述符上的数据尚未准备好,os.read()
似乎会返回一个空字符串。但是,如果我使用 fcntl.fcnt(f.fileno(), fcntl.F_SETFL, fcntl.GETFL | os.O_NONBLOCK)
,那么 os.read
会引发异常 (errno.EWOULDBLOCK
)
我的os.open()
示例中没有设置普通open()
设置的其他标志吗?它们有何不同?为什么?
【问题讨论】:
我建议删除 Python 引用并可能更改此问题的标题。我在处理 Python/C++ 混合项目时碰巧遇到了这个问题,但这绝对不是 Python 的错。就我而言,我试图在 C++ 中创建一个 fifo,然后从 Python 连接到它。自从 C++ 代码挂起后,我从未走到那一步。 要在尝试打开文件之前检查文件是否为 fifo(命名管道),(例如,如果您需要排除它)您可以通过以下方式确定:***.com/questions/8558884/… 第三个语句是错误的(至少在 python3.7 中):open('myfifo', 'w+') 会引发错误:“文件不可搜索”。只有最后 2 个语句有效。 【参考方案1】:这就是它的定义方式。来自 open()
函数的 Open Group 页面
O_NONBLOCK
When opening a FIFO with O_RDONLY or O_WRONLY set: If O_NONBLOCK is
set:
An open() for reading only will return without delay. An open()
for writing only will return an error if no process currently
has the file open for reading.
If O_NONBLOCK is clear:
An open() for reading only will block the calling thread until a
thread opens the file for writing. An open() for writing only
will block the calling thread until a thread opens the file for
reading.
【讨论】:
这正是我所希望的答案(可以说我懒得去追捕自己)。这似乎是一个特别重载 open() 语义的例子,它对 FIFO 来说不同于任何其他类型的文件描述符。我很想从这个问题中删除 Python 标签,因为我怀疑它根本不是 Python 特定的;这恰好是我提供一个我所说的例子的最简单的方法。 是的,Jim Dennis,你不是唯一一个被抛出循环的人。对我来说,这种行为根本不是预期的。我不明白有人如何预测这种行为。在这里,我试图通过仅将管道打开为 O_WRONLY 来编写干净的代码,却发现它挂起(因此我发现自己在这里。)是的,您应该始终阅读文档,但正如 Jim 指出的那样,这似乎改变了语义open
用于特定类的文件描述符。一点也不像 Unix。以上是关于为啥只读打开命名管道块?的主要内容,如果未能解决你的问题,请参考以下文章
为啥我的 (ubuntu 11.10 bash 4.2.10, x86_64 ) 命名管道会堵塞?