BASH/SH 中具有一个 READER 和多个 WRITER 的 FIFO
Posted
技术标签:
【中文标题】BASH/SH 中具有一个 READER 和多个 WRITER 的 FIFO【英文标题】:FIFO with one READER and multiple WRITER in BASH/SH 【发布时间】:2020-10-22 15:56:36 【问题描述】:我有一个命名管道(FIFO)说:'MY_FIFO'
一个进程从多个进程中读取fifo来获取指令。
(1) 阅读器 bash 脚本:
while read LINE < 'MY_FIFO'
do
# process line
done
(许多)编写器 bash 脚本:
while [ 1 ]
do
INSTRUCTION = # get an instruction
echo $INSTRUCTION > 'MY_FIFO'
done
当我们有 1 个写入者或写入者不同时写入时,这可以很好地将指令传递给阅读器。但是,如果我们同时有多个写入器写入,读取器会从最先写入 FIFO 的人那里获得第一条消息,然后挂起等待输入而不是获取下一条指令。
导致我无法让多个写入器写入同一个 fifo 的幕后发生了什么? 他们是否会覆盖彼此的指令?
我有没有办法在写入 fifo 之前测试读取器是否准备好从 fifo 读取?
【问题讨论】:
能否创建一个真正的minimal reproducible example? 不是真正的 bash 或 sh 问题;这是 FIFO 语义的问题,您也可以用 C 编写相同的代码。 (注意,为了确定什么构成“相同代码”,当您退出重定向适用的代码时,文件句柄被显式关闭,并打开一个全新的文件句柄下次您输入该代码块时)。 ...无论如何,解决此问题的一种简单方法是 进行太多更改,即拥有一个flock
风格的独占锁,在任何编写器打开之前都需要持有该锁文件。
@willer2k, ...btw,顺便说一句,请注意,POSIX 规范为修改 shell 或系统实用程序行为的变量指定全大写变量名,而变量名至少有一个小写字符保留“供应用程序使用”,这意味着它们保证不会覆盖修改外壳行为的内容。请参阅pubs.opengroup.org/onlinepubs/9699919799/basedefs/…,请记住环境变量和常规 shell 变量共享一个命名空间(设置 shell 变量将覆盖任何同名环境变量)。
【参考方案1】:
一个问题是,当作者写完它的消息时,它会关闭管道,然后你的阅读器将退出那个循环。当多个进程同时写入时,您还会在管道中收到乱码消息。
你可以试试这个。它在写入时使用flock
锁定管道:
阅读器
#!/bin/bash
while [[ 1 ]]
do
IFS= read -r LINE < MY_FIFO
echo reader got "$LINE"
done
writers - 注意这里先打开管道,然后等待锁成功,最后写入消息:
#!/bin/bash
# getting instructions from stdin for demo purposes
while IFS= read -r INSTRUCTION
do
echo Sending "$INSTRUCTION"
# advisory lock of the pipe when writing
flock MY_FIFO echo "$INSTRUCTION" > MY_FIFO
done
可选的writers - 这会创建一个锁文件并且在实际持有锁之前不会打开fifo。
#!/bin/bash
while IFS= read -r INSTRUCTION
do
echo Sending "$INSTRUCTION"
flock 9
echo "$INSTRUCTION" > MY_FIFO
9> MY_FIFO.lck
done
【讨论】:
这是为输出打开MY_FIFO
以输出 before flock
运行,因为重定向发生在目标命令的 exec
之前。
考虑改为exec lock_fd>MY_FIFO.lck; flock -x "$lock_fd"; echo "$INSTRUCTION" >MY_FIFO; exec lock_fd>&-
——这样编写者在持有锁之前根本不会触及FIFO本身。 (如果需要兼容 4.1 之前的 bash,可以手动分配一个 FD)。
@CharlesDuffy 我还没有修复它,但我在想 - 如果它先打开文件有没有关系,因为它在锁定之前不会写入?
好问题。老实说,我在这里的目标是最大的可预测性 - 只有一个写入器一次打开文件意味着读取器将明确阻止打开操作,直到特定写入器打开文件,并且确保在写入端没有任何内容时写入器之间会有一段时间,因此读取器可以获得 EOF;因此,同步更容易推理。
@CharlesDuffy 我同意。我会添加一个选项。以上是关于BASH/SH 中具有一个 READER 和多个 WRITER 的 FIFO的主要内容,如果未能解决你的问题,请参考以下文章