2012-12-21 7 views
2

명명 된 파이프와 통신하는 두 개의 프로세스를 병렬로 실행했습니다. 나는 이상한 행동을 알아 냈다 : 모든 글은 읽기가 뒤따라야하고 그 반대도 마찬가지이다! 규칙을 위반하면 프로그램이 중단되고 ctrl + C를 사용하여 프로그램을 종료하면 하위 프로그램이 중단되어 더 이상 다시 읽을 수 없습니다.두 프로세스간에 사용되는 명명 된 파이프의 문제점은 무엇입니까?

내 예 : I는 "읽기로 읽기" "에 - 쓰기 - 쓰기"또는 메시지를 삽입 한 점에서

#!/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에서 읽을! 이것을 달성 할 수있는 방법이 있습니까?

답변

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 
+0

네, 그게 내가 이걸 발견 완전한 우연히 오른쪽 대답 (http://stackoverflow.com/questions/4290684/using-named-pipes-with-bash-problem-with-data -loss? rq = 1) 실제로 응답을 지원합니다! 감사! 물론 "얼마나 많은"데이터가 파이프에 보관됩니까? 2^20 바이트 또는 무엇? – centurian

+0

... 그리고 마지막 질문 : 루프 대신에 읽기 - 쓰기 쌍을 사용할 수 있습니까? 코드 효율성에 관해서는 (나는 우리가 파이프를 몇번이고 다시 열었다 고 생각한다.) – centurian

+1

@centurian 명명 된 파이프는 삭제할 때까지 계속 사용되므로 while 루프를 사용하는 것이 매우 효율적이다. 파이프의 크기를 확인하려면, bash에서'ulimit -a'를 사용하여 현재 설정된 파이프 크기를 얻으십시오. 그러나 필자는 언급했듯이 파이프가 가득차면 글쓴이를 차단하고 추가 공간이 있으면 데이터 손실없이 글쓰기를 계속할 것입니다. –