1

script.sh is run by run.sh N times in parallel. For N=1, the script.sh process is set to sleep 30-45 seconds before it actually starts.

How can I order ALL script.sh instances for N>1 not to start until the first (N=1) script.sh comes back from sleeping? The processes cannot communicate directly between each other.

What I want to is tell the other processes that the first one is still sleeping and they have to wait, they will be already initialized, but they cannot execute their code.

The processes also are not able to communicate directly between each other

5
  • 2
    Do you mean run.sh forks N copies of script.sh in parallel? Because if it's sequential then the second (and subsequent) instances of script.sh won't start until the previous one has completed. Unless script.sh forks itself into the background, I suppose. Can you provide a (cut down) example of the code in run.sh that starts up script.sh please. Commented Jun 15, 2016 at 23:28
  • 1
    If you don't want subsquent script.sh processes to do anything until the first one initializes, why start them at all? There are numerous ways you could signal the parent process to continue from the child. You could wait in the parent and have the child fork when ready. You could kill -STOP $$ from the parent and kill -CONT $PPID from the child. You could share a pipe, have the parent block reading, and the child send something on it when ready. You could grab a lock on a file, and release the lock when ready. The list goes on. Commented Jun 16, 2016 at 3:34
  • @roaima yes, parallel. What I want to is tell the other processess that the first one is still sleeping and they have to wait, they will be already initialised, but they cannot execute their code. The processess also are not able to communicate directly between each other Commented Jun 16, 2016 at 9:25
  • 1
    Can you remove the sleep from script.sh and add at the beginning of run.sh? Commented Jun 16, 2016 at 9:45
  • Apart from the given answers, the leading script could create a simple file and the other scripts could use inotifywait to wait for a specific action. Commented Jun 16, 2016 at 14:01

2 Answers 2

1

If you know N beforehand, you can use fifo as a semaphore.

mkfifo sem; exec 3<>sem rm -f sem 

Then make each N>1 process read a byte from that &3. Since those bytes won't initially be available, it'll put them to sleep as well.

Once N==1 is done sleeping, it can write a N bytes into &3, waking up each process that has been waiting on a byte from &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 

Output:

main beg worker1 beg worker2 beg worker3 beg main end worker2 end worker3 end worker1 end 

Another way to do this might be with signals. If you can make sure your script is run as a terminal job with $$ (parent shell pid) being the process group id of the corresponding process group, then you can make your workers sleep indefinitely (ideally with processes calling the pause function; or with sleep $hugevalue if you can't do the former) and before that, make them establish a handler e.g., for SIGUSR1. The main process first worker should ignore the signal. The first worker can then singnal all other workers by kill -SIGUSR1 -$$, which will kill the indefinite sleepers, making the workers continue.

#!/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 

Output:

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 

(I don't know how to turn off the "user-defined signal 1" messages)

2
  • According to the man page trap '' USR1 should ignore SIGUSR1. « If arg is the null string the signal specified by each sigspec is ignored by the shell and by the commands it invokes. » But you've done that (well, almost) so I'm not sure what else is left. Commented Jun 16, 2016 at 12:47
  • I have a space there, though. In any case, I'd recommend against using the signal-based example. It's more fragile than the FIFO solution. Commented Jun 16, 2016 at 12:51
0

Without seeing a snippet of your code I can only guess that it might be something like this:

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

So, in order to wait for the first one to complete before firing off the others you could do something like this:

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

If the script itself takes a significant period of time to run this won't resolve your requirement as written, but unless you can separate the sleep from the processing I don't believe it's going to be sanely possible to achieve your requirement and still satisfy your stated criteria.

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.