3

I would like to start two C codes from a bash file in parallel and the second one stops when the first one has finished. The instruction wait expects both processes to stop which is not what I would like to do. Thanks for any suggestion.

baptiste
  • 95
  • 6

4 Answers4

3

GNU parallel can do this kind of job. Check termination section, it can shutdown down remaining processes based on the exit code (either success or failure:

parallel -j2 --halt now,success=1 ::: 'cmd1 args' 'cmd2 args'

When one of the job finishes successfully, it will send TERM signal to the other jobs (if jobs are not terminated it forces using KILL signal).

Gonzalo Matheu
  • 8,984
  • 5
  • 35
  • 58
  • 1
    Thank you. I have tried this command with GNU parallel 20130922, but and following the tutorial that you indicate in the link but get: Value "now,success=1" invalid for option halt (number expected) – baptiste Sep 04 '17 at 06:03
  • In version *20161222* (Ubuntu 17.04 default version) works. It seems that the change was introduced [during 2015](http://git.savannah.gnu.org/cgit/parallel.git/commit/?id=8110572719461a6019b8f4c22d5ebf43f65cfbe6). Try using *--halt -2*, which seems to be the previous format. – Gonzalo Matheu Sep 04 '17 at 12:44
  • 1
    Ok, that works. And instead of stopping when the first one succeed, it stops when the first one fails. Then I introduced an error at the end of the command that I know will finish first. – baptiste Sep 04 '17 at 15:24
  • If you think this Answer responds to your question, mark it as Accepted. That way it will be removed from Unanswered questions list. More on: https://stackoverflow.com/help/someone-answers – Gonzalo Matheu Sep 12 '17 at 10:24
2

With $! you get the pid of the last command executed in parallel. See some nice examples here: Bash `wait` command, waiting for more than 1 PID to finish execution

For your peculiar problem I imagine something like:

#!/bin/bash

command_master() {
    echo -e "Command_master"
    sleep 1
}
command_tokill() {
    echo -e "Command_tokill"
    sleep 10
}

command_master & pid_master=($!)
command_tokill & pid_tokill=($!)
wait "$pid_master"
kill "$pid_tokill"
Picaud Vincent
  • 10,518
  • 5
  • 31
  • 70
  • Thank you. The process to kill is a C code which I'd like to tell that it is going to be killed and have time to close files before. Basically send a signal from the master to the process to kill such that it enters a loop and does final operations before being killed. Is that possible? – baptiste Sep 04 '17 at 07:21
  • For example, when the master is done, send an integer to the C file, runMe.c with runMe 1 such that it enters a final loop in the C code. – baptiste Sep 04 '17 at 07:59
  • I understand your problem. Unfortunately, I haven't a clean bash solution to propose. For a clean solution, one must take care of some synchronizations and I do not know if bash is really convenient for that. In my example, for instance, there is no protection against the following scenario: the "toKill" process ends before "master" process. If during wait "$pid_master", the OS starts another process with the same PID as the previous "toKill" one, then the bash instruction kill "$pid_tokill" will kill the wrong process. – Picaud Vincent Sep 04 '17 at 08:43
  • this is quite unlikely as AFAIK on *nix PID are generated in an incremental way (once a limit is reached, allocation restarts at zero and again increases, skipping still existing PID). But the solution is not clean.... – Picaud Vincent Sep 04 '17 at 08:53
1

wait -n is what you are looking for. It waits for the next job to finish. You can then have a list of the PIDs of the remaining jobs with jobs -p if you want to kill them.

xhienne
  • 5,738
  • 1
  • 15
  • 34
1
prog1 & pids=( $! )
prog2 & pids+=( $! )

wait -n

kill "${pids[@]}"

This requires bash.

The two programs are started as background jobs, and the shell waits for one of them to exit.

When this happens, kill is used to terminate both processes (this will cause an error since one of them is already dead).

Kusalananda
  • 14,885
  • 3
  • 41
  • 52