Как заставить несколько процессов "общаться" вместе?
Я пытаюсь смоделировать игру для двух игроков в bash. Точнее, должна быть одна центральная программа (движок игры) и две программы для игроков. Игровой движок должен отправить информацию об игре в player1, затем получить вывод player1, затем отправить информацию об игре в player2, затем получить вывод player2 и повторить.
Если это вообще возможно, я бы предпочел, чтобы игровой движок не отвечал за распределение своих выходных данных, а вместо этого использовал бы сценарий bash для планирования всего этого.
Прочитав материал о именованных каналах, я понял, что это именно то, что мне нужно, и предложил следующую настройку:
#!/bin/bash
trap "rm -f $in1 $in2 $out1 $out2 $in $out; kill $pid; kill $pid1; kill $pid2" KILL
in1=/tmp/testpipe_in1
in2=/tmp/testpipe_in2
out1=/tmp/testpipe_out1
out2=/tmp/testpipe_out2
in=/tmp/testpipe_in
out=/tmp/testpipe_out
for p in $in1 $in2 $out1 $out2 $in $out; do
[[ -p $p ]] || mkfifo $p
done
echo 0 > $in
./center.sh < $in > $out &
pid=$!
./player1.sh < $in1 > $out2 &
pid1=$!
./player2.sh < $in2 > $out2 &
pid2=$!
i=0
while true; do
i=$((i+1))
echo "Round $i" >&2
cat < $out > $in1
cat < $out1 > $in
cat < $out > $in2
cat < $out2 > $in
done
Я тестирую это со следующей игрой и игроками:
center.sh
:
#!/bin/bash
while true; do
sleep 2
read i
echo "Center : $i $((i+2))" >&2
echo $((i+2))
done
player1.sh
:
#!/bin/bash
while true; do
sleep 1
read i
echo "Player1 : $i $((i-1))" >&2
echo $((i-1))
done
player2.sh
:
#!/bin/bash
while true; do
sleep 1
read i
echo "Player2 : $i $((i+1))" >&2
echo $((i+1))
done
Я ожидал, что это выведет что-то вроде
Center : 0 2
Round 1
Player1 : 2 1
Center : 1 3
Player2 : 3 4
Center : 4 6
Round 2
Player1 : 6 5
...
... но, конечно, это не работает.
Вместо этого я получаю:
Round 1
Center : 0 2
Center : 2
Center : 2
...
Является ли проблема чем-то очевидным в моих игроках? Или как правильно настроить этот вид диспетчеризации входов / выходов?
1 ответ
Вот некоторые изменения, которые могут продвинуть вас дальше:
в первом сценарии есть опечатка. Так должно быть:
./player1.sh < $in1 > $out1 &
то есть out1 не out2.
переместить
echo 0 > $in
после запуска игроков.изменить финал
while
цикл до:while true; do i=$((i+1)) echo "Round $i" >&2 read <&5; echo "$REPLY" >&6 read <&7; echo "$REPLY" >&8 read <&5; echo "$REPLY" >&9 read <&4; echo "$REPLY" >&8 done 5<$out 6>$in1 7<$out1 8>$in 9>$in2 4<$out2
Первоначально читатель fifo блокируется, пока писатель не пишет в fifo. Когда автор закрывает fifo, читатель читает eof, но больше не блокируется, поэтому продолжает читать eof, пока автор снова не откроет fifo и не запишет снова. Вам нужно будет проверить код возврата read
и снова откройте fifo как читателя, чтобы снова заблокировать.
Вы можете легко увидеть это с помощью:
while sleep 1; do read;echo "$? $REPLY";done <testpipe_out1 &
sleep 5
echo hi >testpipe_out1
Чтение будет блокироваться до "привет", затем цикл с кодом возврата "1".