【问题标题】:Bash redirection: named pipes and EOFBash 重定向:命名管道和 EOF
【发布时间】:2015-10-15 22:55:37
【问题描述】:

取以下代码:

rm -f pipe
mkfifo pipe

foo () {
    echo 1
    sleep 1
    echo 2
}

#1
exec 3< <(foo &)
cat <&3 # works

#2
foo >pipe &
cat <pipe # works

#3
exec 3<>pipe
foo >&3 &
cat <&3 # hangs

#4 -- update: this is the correct approach for what I want to do
foo >pipe &
exec 3<pipe
rm pipe
cat <&3 # works

为什么方法 #3 会挂起,而其他方法则不会?有没有办法让方法 #3 不挂起?

理由:我希望使用准无名管道来连接几个异步运行的子进程,为此我需要在文件描述符指向它后删除管道:

mkfifo pipe
exec {fd}<>pipe
rm pipe
# use &$fd only

【问题讨论】:

    标签: bash named-pipes io-redirection process-substitution


    【解决方案1】:

    方法 3 中的问题是 FIFO pipe 然后有 2 个写入器:bash 脚本(因为您已使用 exec 3&lt;&gt; 读取/写入打开它)和运行 foo 的子 shell。当所有作者都关闭文件描述符时,您将读取 EOF。一个编写器(运行foo 的子shell)将很快退出(大约1 秒后)并因此关闭文件描述符。然而,另一个编写器(主 shell)仅在文件描述符退出时关闭文件描述符,因为在任何地方都没有关闭文件描述符 3。但它无法退出,因为它等待cat 先退出。这是一个僵局:

    • cat 正在等待 EOF
    • EOF 仅在主 shell 关闭 fd(或退出)时出现
    • 主 shell 正在等待 cat 终止

    因此你永远不会退出。

    案例 2 有效,因为管道只有一个写入器(运行 foo 的子 shell),它退出非常快,因此将读取 EOF。在情况 1 中,也只有一个写入器,因为您以只读方式打开 fd 3 (exec 3&lt;)。

    编辑:删除关于案例 4 不正确的废话(参见 cmets)。这是正确的,因为在阅读器连接之前编写器无法退出,因为在阅读器尚未打开时打开文件时它也会被阻止。 不幸的是,新添加的案例 4 不正确。它很活泼,只有当fooexec 3&lt;pipe 运行之前没有终止(或关闭管道)时才有效。

    同时查看fifo(7) 手册页:

    内核为每个由至少一个进程打开的 FIFO 特殊文件维护一个管道对象。 FIFO 必须在两端(读取和写入)都打开,才能传递数据。通常,打开FIFO会阻塞,直到另一端也打开。

    【讨论】:

    • 成功了。 exec 3&lt;&gt; 使主 shell 成为编写器,这会导致 EOF 问题。
    • @Irfy 我补充说。在情况 1 中,文件描述符 3 在主 shell 中以只读方式打开。因此,管道永远不会有超过 1 个作者。
    • 在此帮助下,我重写了删除管道的代码,使其按预期工作,谢谢。
    • @Irfy 不幸的是,#4 也不是真的正确。这实际上是一个竞争条件:如果 fooexec 3&lt;pipe 运行之前退出,exec 3&lt;pipe 将挂起,直到另一个编写器打开 pipe
    • @Irfy 是的,你说得对!编写器 (foo &gt;pipe ) 仅在读取器 (exec 3&lt;pipe) 连接时开始运行。所以你们都很好。很抱歉造成混乱。
    猜你喜欢
    • 1970-01-01
    • 2019-02-10
    • 1970-01-01
    • 2017-12-31
    • 2014-12-21
    • 1970-01-01
    • 2019-11-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多