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

时间:2012-12-21 14:19:24

标签: 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)

谢谢!

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

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

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读取的!有没有办法实现这个目标?

1 个答案:

答案 0 :(得分:2)

管道拥有的数据量有限。如果在它们满之前写入它们,则所有将来的写入都将阻塞,直到读出数据。同样,如果管道中没有要读取的数据,则读取阻塞。

最重要的是,在你做事之前,你需要管道两侧的人。因此,在您编写第二条消息后,您会遇到读者查看管道的情况。因此,就其而言,没有数据。然后,您的主要流程结束,并让孩子闲逛。

要解决此问题,请勿关闭阅读器端。使用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