【发布时间】:2019-08-02 19:25:49
【问题描述】:
我有一个 Python 程序,它将命名管道用于各种目的。 每个管道都由不同的线程管理,因此不会阻塞主线程。
假设我有一个线程阻塞了对open('in', 'rb') 的调用,其中in 是命名管道的相对路径。
如果我想关闭我的程序,我会使用这样的东西来解除我的线程与另一个线程的阻塞:
with suppress(OSError):
fd = os.open('in', O_WRONLY | O_NONBLOCK)
os.close(fd)
这只是以写入模式打开管道,以便open 上的线程阻塞可以继续,然后关闭它。我使用O_NONBLOCK 来避免在另一个线程已经终止的情况下阻塞(并忽略潜在的OSError)。
这工作正常,直到有人决定删除命名管道 in 而我的线程阻塞在 open 上。
在这种情况下,我不能使用我的“尝试以非阻塞模式打开管道并关闭它”方法,因为管道在文件系统上不再可见(并且非阻塞打开只会创建一个全新的管道)。
除了杀死线程之外,这个问题的正确解决方案是什么? 请注意,我无法阻止其他进程删除管道,并且权限也无济于事(删除进程可以以 root 身份运行)。
【问题讨论】:
-
最坏的情况我可以使用非阻塞打开来轮询管道,而不是在打开它时显式阻塞,但我发现阻塞方法更优雅,因为轮询需要浪费 CPU 周期并引入了时间因素。
-
您的问题听起来像一个 XY 问题(到底为什么有人会首先使用命名管道?)。但是如果你设置了一个信号处理程序,发送信号将中断阻塞的 open() 系统调用,让你的程序在处理完 EINTR 错误后继续。所以你可以发送一个信号而不是那个打开/关闭技巧。
-
@mosvy 我必须使用命名管道(说来话长)。在 Python (3.7) 中可以做到这一点吗?文档说:“Python 信号处理程序总是在 Python 主线程中执行,即使信号是在另一个线程中接收到的。这意味着信号不能用作线程间通信的手段。”
-
信号处理程序不需要做任何事情;只是为了中断 open() 系统调用。请参阅“答案”(我不是 python 程序员,所以这可能不是最好的方法)。另一个想法是使用
O_RDWR打开命名管道(这将不会阻塞)——但在这种情况下,您无法通过 EOF 确定作者何时关闭了管道的末端。跨度> -
似乎没有办法a)在python中获取真正的线程ID(为了向特定线程发送信号所必需的)和b)在python3中处理EINTR - 所有系统调用都将是由解释器手动重新启动(尽管在 python2 中仍然可以)。因此,唯一的解决方法是以读写模式打开命名管道(所有现代系统都支持)。
标签: python-3.x unix pipe posix named-pipes