如何避免并行命名管道的死锁?

how to avoid deadlock with parallel named pipes?

我正在研究 a flow-based programming system called net2sh。它目前基于 shell 由命名管道连接的工具。多个进程协同工作以完成工作,通过命名管道进行通信,这与工厂中的生产线没有什么不同。

总的来说,它运行良好,但有一个主要问题。在进程通过两个或多个命名管道进行通信的情况下,"sending" 进程和 "receiving" 进程必须以相同的顺序打开管道。这是因为当进程打开命名管道时,它会阻塞,直到另一端也被打开。

我想要一种避免这种情况的方法,不需要为每个管道产生额外的 "helper" 进程,不需要破解现有组件,也不需要为了避免这个问题而扰乱程序网络。

理想情况下,我正在寻找一些 "non-blocking fifo" 选项,其中 fifo 上的 "open" 总是立即成功,但如果管道缓冲区已满(或为空,用于读取),后续操作可能会阻塞。 . 我什至会考虑使用内核补丁来达到这种效果。根据 fifo(7) O_NONBLOCK 在打开 fifos 时确实做了一些不同的事情,而不是我想要的,并且为了使用它我必须重写每个现有的 shell 工具,例如 cat.

这是一个死锁的最小示例:

mkfifo a b
(> a; > b; ) &
(< b; < a; ) &
wait

如果您能帮助我明智地解决这个问题,我将不胜感激!

这里有关于使用 O_NONBLOCK 和命名管道的很好的描述:How do I perform a non-blocking fopen on a named pipe (mkfifo)?

听起来您希望它在您的整个环境中工作而不更改任何 C 代码。因此,一种方法是将 LD_PRELOAD 设置为某个共享库,其中包含 open(2) 的包装器,每当 pathname 引用一个时,它将 O_NONBLOCK 添加到 flags命名管道。

此处是使用 LD_PRELOAD 覆盖库函数的简明示例:https://www.technovelty.org/c/using-ld_preload-to-override-a-function.html

这是否真的在实践中起作用而不破坏其他任何东西,您必须自己找出答案(请告诉我们!)。