Почему ожидание не может работать для процесса чтения в именованном канале?

wait в bash предназначен для изменения состояния процесса. В следующем сценарии bash создайте именованный канал и откройте 5 процессов для записи в него потока данных и откройте 1 процесс для чтения потока данных из него в другой файл.

cat pipe.sh
fifo_file=fifo.pipe
mkfifo $fifo_file
exec 6<>$fifo_file
rm $fifo_file

DateWrite ()
{
    i=0
    while [[ $i -lt 200 ]]
    do
        str=`date`
        i=$(( i+1 ))
        echo "$i $str"
    done
}

writers=()
for  (( i=0; i<5; i++ ))
do 
    DateWrite >&6  & 
    echo "add a writer process pid  $!"
    writers+=($!)
done


while read date_time
do
    echo $date_time >> output.file 
done  <&6  &
reader=$!

for writer in "${writers[@]}" 
do
    wait "$writer"
    echo "the status of writer process pid $writer changed"   
done

echo "reader process pid is $reader"
wait  "$reader"
echo "the status of reader process pid $reader changed"   

exec 6<&-

Чтобы проверить команду ожидания в pipe.sh с помощью bash pipe.sh.

add a writer process pid  4749
add a writer process pid  4750
add a writer process pid  4751
add a writer process pid  4752
add a writer process pid  4753
the status of writer process pid 4749 changed
the status of writer process pid 4750 changed
the status of writer process pid 4751 changed
the status of writer process pid 4752 changed
the status of writer process pid 4753 changed
reader process pid is 4754

Список информации не содержит

the status of reader process pid 4754 changed

Оператор wait "$reader" выполняется в бесконечном цикле while, это нормально, что wait не может работать.
Если я удалю две строки:

wait  "$reader"
echo "the status of reader process pid $reader changed"   

И выполните bash pipe.sh :

add a writer process pid  19670
add a writer process pid  19671
add a writer process pid  19673
add a writer process pid  19674
add a writer process pid  19675
the status of writer process pid 19670 changed
the status of writer process pid 19671 changed
the status of writer process pid 19673 changed
the status of writer process pid 19674 changed
the status of writer process pid 19675 changed
reader process pid is 19676

Найдите pid 19676 в консоли.

ps aux |grep '[p]ipe'
debian   19676  0.0  0.0  16516  2100 pts/1    S    19:54   0:00 bash pipe.sh

Процесс чтения, созданный в pipe.sh, все еще выполняется после завершения pipe.sh.
Я не хочу менять wait "$reader" на kill "$reader" в pipe.sh.
Есть ли способ узнать, что echo $date_time прочитал конец канала, и отправить сигнал закрыть процесс чтения?

@Philippe и все друзья здесь, sleep 1; echo q >&6, может быть, временной интервал такой короткий. Предположим, более сложный случай:

while read date_time
do
    test "$date_time" = q && exit
    echo $date_time >> output.file 
    bash_some_code_do_some_thing
done  <&6  &

Время выполнения bash_some_code_do_some_thing больше 10 секунд, минимум 10 секунд, не больше 10 секунд, и вы не можете оценить точное время. Вы не можете написать такой код, как

sleep 10; echo q >&6

or

спать 100; echo q >&6 #что делать, если время работы больше на 200 секунд?

Как тогда решить дело?


person showkey    schedule 05.05.2020    source источник
comment
Вы закрываете FD 6 после ожидания завершения чтения, но чтение не завершится, пока FD 6 не будет закрыт.   -  person l0b0    schedule 05.05.2020
comment
Пожалуйста, смотрите мой обновленный пост, это не причина, close FD 6 не связана с этим.   -  person showkey    schedule 05.05.2020


Ответы (1)


Невозможно отправить EOF в канал, открытый для чтения и записи. Одним из обходных путей является отправка команды quit:

fifo_file=fifo.pipe
mkfifo $fifo_file
exec 6<>$fifo_file
rm $fifo_file

DateWrite ()
{
    i=0
    while [[ $i -lt 200 ]]
    do
        str=`date`
        i=$(( i+1 ))
        echo "$i $str"
    done
}

writers=()
for  (( i=0; i<5; i++ ))
do 
    DateWrite >&6  & 
    echo "add a writer process pid  $!"
    writers+=($!)
done


while read date_time
do
    test "$date_time" = q && exit
    echo $date_time >> output.file 
done  <&6  &
reader=$!

for writer in "${writers[@]}" 
do
    wait "$writer"
    echo "the status of writer process pid $writer changed"   
done

echo "reader process pid is $reader"
sleep 1; echo q >&6
wait  "$reader"
echo "the status of reader process pid $reader changed"   

exec 6<&-

Другой способ — послать считывателю сигнал TERM.

person Philippe    schedule 05.05.2020