在2个进程(第3个)之间使用命名管道有什么问题?

时间:2012-12-24 11:39:56

标签: bash process parallel-processing named-pipes

经过大约100次组合后,我得到了以下代码,它使用一个进程作为服务器,用管道来读取客户端的响应,我称之为“伦敦”函数,它是管道'london_pipe'(我很不自然地打电话给我管道'伦敦'也因为命名冲突?)。 在下面,有2个客户端,每个客户端与自己的管道通信,服务器用来读取数据。我遵循相同的命名约定,使用用于读取的函数名称命名管道。所以,'berlin'正在读'berlin_pipe'等。

整体结构使用1个管道到1客户端和1个管道用于服务器,如下所示:

london ----writes madrid pipe-------->
london <----reads london_pipe----<-  |
london ----writes berlin_pipe---> |  |
                                | ^  |
                                | |  |
berlin <---reads berlin_pipe--<-  |  |
berlin ----writes london_pipe-----|  |
                                  ^  |
                                  |  |
madrid ----writes london_pipe------  v
madrid <----reads madrid_pipe------<-

现在,当我运行我的代码时,我面临一个非常奇怪的情况,我的客户端反复读取空字符串 - 我已经构建了我的程序 - 他们响应向服务器发送误报!当我添加if子句(参见代码中的注释)时,问题就消失了!

有人可以解释我管道的奇怪行为吗?或者代码本身存在一些问题?

简而言之,一些澄清: 代码

while true; do
.......
done 4<"$pipename"

适用于所有客户端,即使每次重复使用fd 4指向不同的管道也是如此。 现在代码:

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

DIR=$( cd "$( dirname "$0" )" && pwd )

#the server
function london (){
   local i message answer london_pipe berlin_pipe madrid_pipe
   london_pipe=london_$RANDOM.$RANDOM.$RANDOM.$$
   madrid_pipe=madrid_$RANDOM.$RANDOM.$RANDOM.$$
   berlin_pipe=berlin_$RANDOM.$RANDOM.$RANDOM.$$
   cd $DIR
   mkfifo $london_pipe
   mkfifo $madrid_pipe
   mkfifo $berlin_pipe
   ( madrid $madrid_pipe $london_pipe ) &
   ( berlin $berlin_pipe $london_pipe ) &
   i=0

   while true; do
      if [[ i -gt 100 ]]; then
         echo 'quit' > $madrid_pipe
         echo 'quit' > $berlin_pipe
         break
      else
         echo "loop #$i"
         echo '========='
         message="London loop (#$i)"

         #***send to Madrid***#
         echo "$message" > $madrid_pipe

         read -r answer <&3
         echo 'London says:> '"$answer"

         #***send to Berlin***#
         echo "$message" > $berlin_pipe

         read -r answer <&3
         echo 'London says:> '"$answer"
         (( i++ ))
      fi
   done 3< $london_pipe

   wait
   cd "$DIR"
   rm -rf $london_pipe
   rm -rf $madrid_pipe
   rm -rf $berlin_pipe
}

#a client
function berlin (){
   local i message answer berlin_pipe london_pipe
   berlin_pipe=$1
   london_pipe=$2
   cd $DIR
   i=0
   exec 3> $london_pipe
   while true; do

      read -r answer <&4
      #***if deleted it reads empty strings!!!***#
      if [[ ! $answer ]]; then
         continue
      fi
      echo 'Berlin says:> '"$answer"

      message="Greetings from Berlin!($i)"
      echo "$message" >&3
  (( i++ ))

      if [[ $answer = 'quit' ]]; then
         break
      fi
   done 4< "$berlin_pipe"
}

#another client
function madrid (){
   local i message answer madrid_pipe london_pipe
   madrid_pipe=$1
   london_pipe=$2
   cd $DIR
   i=0
   exec 3> $london_pipe
       while true; do

      read -r answer <&4
      #***if deleted it reads empty strings!!!***#
      if [[ ! $answer ]]; then
         continue
      fi
      echo 'Madrid says:> '"$answer"

      message="Greetings from Madrid!($i)"
      echo "$message" >&3
      (( i++ ))

      if [[ $answer = 'quit' ]]; then
         break
      fi
   done 4< "$madrid_pipe"
}

london

if-code是这个块

      #***if deleted it reads empty strings!!!***#
      if [[ ! $answer ]]; then
         continue
      fi

有了这些结果:

loop #97
=========
Madrid says:> London loop (#97)
London says:> Greetings from Madrid!(97)
Berlin says:> London loop (#97)
London says:> Greetings from Berlin!(97)

没有两个客户:

loop #91
=========
Madrid says:> London loop (#86)
Madrid says:> London loop (#87)
Madrid says:> London loop (#88)
Madrid says:> London loop (#89)
Madrid says:> London loop (#90)
Madrid says:> 
Madrid says:> 
Madrid says:> 
很明显,'madrid'确实读取了空字符串以及来自'london'的消息,其中循环编号为86等,这些消息已被先前的空读取推,现在已经出现故障。 有人可以解释一下吗?

由于

1 个答案:

答案 0 :(得分:1)

问题是你如何写london中的管道:echo "$message" > $madrid_pipe 这会打开和关闭每次写入的管道,这与您在保持管道打开的其他端点中的操作不同。这会造成竞争条件:如果berlinmadrid恰好在管道关闭时尝试阅读,则其读取将不返回任何数据,请参阅man 7 pipe

  

如果引用管道写入端的所有文件描述符都已存在   关闭,然后尝试从管道读取(2)将看到   文件结束(read(2)将返回0)。

解决方案很简单,要么像你一样处理,要么确保london保持管道打开。