Se você sabe N antecipadamente, você pode usar o fifo como um semáforo.
mkfifo sem;
exec 3<>sem
rm -f sem
Em seguida, faça cada processo N > 1 ler um byte desse &3
.
Como esses bytes não estarão inicialmente disponíveis, também os colocarão em suspensão.
Uma vez que N == 1 termine de dormir, ele pode escrever um N bytes em & 3, despertando cada processo que está esperando em um byte de & 3.
#!/bin/bash -e
mkfifo p
exec 3<>p
rm p
main()(
echo $FUNCNAME beg
sleep 2 &>/dev/null
printf '\n\n\n' >&3
echo $FUNCNAME end
)
worker()(
echo $FUNCNAME$1 beg
read -n 1 <&3
echo $FUNCNAME$1 end
)
main &
worker 1 &
worker 2 &
worker 3 &
wait
Saída:
main beg
worker1 beg
worker2 beg
worker3 beg
main end
worker2 end
worker3 end
worker1 end
Outra maneira de fazer isso pode ser com sinais.
Se você puder garantir que seu script seja executado como uma tarefa de terminal com $$
(pid pai shell) sendo o ID do grupo de processos correspondente, você poderá fazer seus trabalhadores dormir indefinidamente (de preferência com processos chamando o pause
função, ou com sleep $hugevalue
se você não pode fazer o primeiro) e antes disso, fazê-los estabelecer um manipulador, por exemplo, para SIGUSR1. O primeiro trabalhador do processo principal deve ignorar o sinal.
O primeiro trabalhador pode então cingir todos os outros trabalhadores em kill -SIGUSR1 -$$
, o que matará os dormentes indefinidos, fazendo com que os trabalhadores continuem.
#!/bin/bash
trap ' ' SIGUSR1
main()(
trap - SIGUSR1
echo $FUNCNAME beg
sleep 2 &>/dev/null
echo $FUNCNAME end
kill -s SIGUSR1 -$$
)
worker()(
trap ' ' SIGUSR1
echo $FUNCNAME$1 beg
sleep 10000000000 &>/dev/null
echo $FUNCNAME$1 end
)
main &
worker 1 &
worker 2 &
worker 3 &
wait
Saída:
main beg
worker2 beg
worker1 beg
worker3 beg
main end
User defined signal 1
worker1 end
User defined signal 1
worker3 end
User defined signal 1
[1] 31554 user-defined signal 1 ./scr1
(não sei como desativar as mensagens "user-defined signal 1"
)