bash - 两个进程之间使用命名管道有什么问题?

标签 bash named-pipes read-write

我让 2 个进程并行运行,并与命名管道进行通信。 我注意到一个奇怪的行为:每次写入后都应该进行读取,反之亦然! 如果我们违反规则,程序将挂起,如果我们使用 ctrl+C 终止它,子级仍然挂起,这意味着它无法再重新读取。

我的例子:

#!/bin/bash
shopt -u failglob
shopt -s extglob nullglob dotglob

function london (){
   local message answer fifo id return exitcode
   fifo=fifo_$RANDOM.$RANDOM.$RANDOM.$$
   mkfifo ${fifo}
   #trap 'rm -rf "$fifo"' EXIT
   ( berlin $fifo ) &
   id=$!
   echo "parent id: $$, child id: $id"
   message='Greetings from London!(1)'
   echo "$message" > $fifo
   echo "1. parent sent it's 1st message"
   #*****write-to-write error!*****#
   message='Greetings from London!(2)'
   #read -r answer < $fifo
   echo "$message" > $fifo
   echo "2. parent sent it's 2nd message"
   wait
   rm -rf $fifo
}

function berlin (){
   local message answer fifo
   fifo=$1
   read -r answer < $fifo
   echo 'Berlin says:> '"$answer"
   #*****read-to-read error!*****#
   #echo 'next' > $fifo
   read -r answer < $fifo
   echo 'Berlin says:> '"$answer"
}

london

在我插入“写到写”或“读到读”消息的点下,有 2 行注释行解决了问题,让我认为上述规则神秘地成立! 有什么想法吗?

这是输出:

parent id: 4921, child id: 4923
1. parent sent it's 1st message
2. parent sent it's 2nd message
Berlin says:> Greetings from London!(1)

谢谢!

我认为现在一切都清楚了,并且浓缩在一个短语中:“让读者保持管道畅通”

现在假设,我想为循环内的“某些”命令添加第二个输入文件描述符;我怎样才能做到这一点? 这是我的新柏林函数:

function berlin (){
   local message answer fifo
   fifo=$1
   while true; do
      read -r answer
      echo 'Berlin says:> '"$answer"
      #this fails!
      read -r -p "reading from fd0: " <&0
      if [[ $answer = 'quit' ]]; then
         break
      fi
   done < "$fifo" 3>"$fifo"
}

正如我们所看到的,我们使用文件描述符 3 作为管道,但是当我们尝试从 fd 0 读取时,我们实际上是从 fd 3 读取!有办法实现吗?

最佳答案

管道可以容纳的数据量是有限的。如果您写入它们直到它们已满,则所有 future 的写入都将阻塞,直到数据被读出。同样,如果管道中没有数据可供读取,则读取 block 。

最重要的是,在你做事之前,你需要两边都有人。因此,您会遇到这样的情况:在您写完第二条消息后,读者会查看管道。所以,就目前而言,没有数据。然后,您的主要进程完成,并让子进程闲逛。

要解决此问题,请不要关闭阅读器端。使用 while 循环来保持该端打开。就像这样:

#!/bin/bash
shopt -u failglob
shopt -s extglob nullglob dotglob

function london (){
   local message answer fifo id return exitcode
   fifo=fifo_$RANDOM.$RANDOM.$RANDOM.$$
   mkfifo ${fifo}
   #trap 'rm -rf "$fifo"' EXIT
   ( berlin $fifo ) & 
   id=$!
   echo "parent id: $$, child id: $id"
   message='Greetings from London!(1)'
   echo "$message" > $fifo
   echo "1. parent sent it's 1st message"
   #*****write-to-write error!*****#
   message='Greetings from London!(2)'
   #read -r answer < $fifo
   echo "$message" > $fifo
   echo "2. parent sent it's 2nd message"
   wait
   rm -rf $fifo
}

function berlin (){
   local message answer fifo
   fifo=$1
   while read -r answer
   do  
       echo 'Berlin says:> '"$answer"
   done < $fifo
}

london

关于bash - 两个进程之间使用命名管道有什么问题?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13991790/

相关文章:

c++ - Windows 7 中的命名管道

linux - 命名管道到常规文件

C#:异步NamedPipeServerStream的理解

c - 从 1 个管道读取多个写入器

python - 如何将 pandas 数据帧逐行写入 CSV 文件,一次一行?

bash - 语法错误表达式

bash - 如何在 BusyBox 上使用 float ?

linux - Bash:如何拖尾然后复制多个文件(例如使用 xargs)?

sockets - 同步读取和写入到 TCP 套接字

bash - 我如何回显/打印来自 bash 变量的特定行