并发写入mkfifo似乎丢失了

时间:2018-11-10 14:08:46

标签: linux bash unix pipe named-pipes

我正在编写一个脚本来设置机器环境。我能够在计算机上放置启动脚本,因此我试图在我的“工作站”计算机上的Unix中使用命名管道mkfifo,当这些新计算机联机时,它们将侦听来自这些新计算机的写入。 / p>

问题是,我无法控制这些计算机何时可以联机。总共有超过20台机器正在同时启动,我试图模拟命名管道被多次写入的效果,然后它才有机会读取并产生令人吃惊的结果。...

我写了两个小的测试脚本:

mkfifogen.sh

#!/bin/bash
mkfifo h
testing=""
sleep 10
for((i=0;i<5;i++));do
    echo $I
    while read line;do
       testing+="$line"
    done < h
done

echo "$testing"
rm -f h

mkfifowrite.sh

#!/bin/bash
for((i=0;i<5;i++));do
    echo "this is a test $i" > h
done

当我先运行mkfifogen.sh之后再运行mkfifowrite.sh时,输出如下所示

0
1
2

然后,mkfifowrite.sh脚本退出并且mkfifogen.sh脚本挂起

然后我必须再运行mkfifowrite.sh脚本3次,并且每次它都会导致mkfifogen.sh脚本的输出再增加一次。上一次运行将导致测试值输出4次,因此在运行4次mkfifowrite.sh脚本和运行一次mkfifogen.sh脚本后,我的输出如下所示:

0
1
2
3
4
this is a test 0this is a test 1this is a test 2this is a test 3this is a test 4
this is a test 0this is a test 1this is a test 2this is a test 3this is a test 4
this is a test 0this is a test 1this is a test 2this is a test 3this is a test 4
this is a test 0this is a test 1this is a test 2this is a test 3this is a test 4

运行mkfifogen.sh和mkfifowrite.sh一次后,我希望看到的内容是这样的:

0
1
2
3
4
this is a test 0this is a test 1this is a test 2this is a test 3this is a test 4

我已经在网上四处逛逛了,对此有一些神秘的答案,但是我似乎对它们没有多大意义。我觉得此链接可能会保留我的答案,但是我不确定https://unix.stackexchange.com/questions/68146/what-are-guarantees-for-concurrent-writes-into-a-named-pipe

TL; DR:

如何确保所有对命名管道的写入,无论它们连续执行的快慢如何,均由读取独立处理?

1 个答案:

答案 0 :(得分:0)

阅读器读取直到EOF,然后重复直到收到5个EOF。

编写器打开和关闭管道5次。编写器每次关闭管道时,都会存在潜在的EOF条件。直到读者尝试读取它(在读取之前编写的所有内容之后),它才成为真正的EOF。

在潜在的EOF阶段,有一场比赛。编写器正在递增i并准备打开管道以再次写入,而阅读器正在完成read命令并处理结果,然后它将尝试再次读取。

如果在阅读器尝试进行读取之前,写入器执行了打开操作,则潜在的EOF条件消失。如果在写入器不再连接到管道时读取器尝试读取,则会发生EOF。

如您所见,当一个管道有多个写入器时(无论是顺序写入器还是并行写入器),EOF会很麻烦。您不能期望它们能够可靠地出现在来自不同作者的消息之间。我的解决方法是设计协议,以使阅读器不需要EOF来识别消息的结尾,然后让阅读器以读+写模式打开管道,这样总是至少是一名现有作家,并且EOF将永远不会发生。

将邮件保持在PIPE_BUF大小以免被拆分是一个单独的问题,您也必须注意。