Aguarde até que um processo volte do modo de espera

1

script.sh é executado por run.sh N vezes em paralelo. Para N = 1 , o processo script.sh é definido para dormir entre 30 e 45 segundos antes de realmente começar.

Como posso solicitar TODAS as instâncias script.sh para que N > 1 não inicie até que o primeiro ( N = 1 ) script.sh volta do sono? Os processos não podem se comunicar diretamente entre si.

O que eu quero é dizer aos outros processos que o primeiro ainda está dormindo e eles têm que esperar, eles já estarão inicializados, mas eles não podem executar seu código.

Os processos também não são capazes de se comunicar diretamente entre si

    
por siqero 16.06.2016 / 01:23

2 respostas

1

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" )

    
por 16.06.2016 / 14:19
0

Sem ver um snippet do seu código, só posso imaginar que pode ser algo assim:

for k in $(seq $N)
do
    script.sh &
done

Então, para esperar que o primeiro seja concluído antes de disparar os outros, você pode fazer algo assim:

for k in $(seq $N)
do
    script.sh &
    [[ $k == 1 ]] && wait
done

Se o script em si levar um período de tempo significativo para ser executado, isso não resolverá seu requisito como está escrito, mas, a menos que você possa separar o sono do processamento, não acredito que seja possível alcançar sua necessidade e ainda satisfazer seus critérios declarados.

    
por 16.06.2016 / 13:34