Multithreading Bash If Statements
If you want each if
condition to execute within the context of its respective "thread" (actually subshell process), then I think the thing to do is put the &
after the closing fi
statement for each if
. Then the evaluation of each if
expression, along with conditional code wiil occur entirely within the context of its own "thread".
For example:
#/bin/bashif [ 1 ] then for i1 in {1..3}; do echo $i1; sleep 1; donefi &if [ 1 ] then for i2 in {a..c}; do echo $i2; sleep 1; donefi &wait
Output from each "thread" is interleaved as expected:
1a2b3c
Note in all cases with &
, these are actually processes (created with fork()
) and not threads (created with pthread_create()
). See Multithreading in Bash. You can test this by creating a variable, e.g. n=0
before the "threads" are started. Then in one thread increment n and echo $n in all threads. You'll see each "thread" gets its own copy of n - n will have different values in the incrementing and non-incrementing threads. fork()
creates a new process copy (including independent copies of variables); pthread_create()
doesn't.
Placing the &
after the if
will only background the evaluation of the conditional expression ; [
is actually an alias for the test
command, and that is what will be backgrouded, and not the task.
Placing the &
after the task will background the task. The degree to which the tasks are staggered rather than simultaneous depends on the relative time needed to evaluate expr1
compared to the time needed to perform task1
See the following script:
#!/bin/bashif [ 1 ] &then sleep 10 fiif [ 1 ] &then sleep 10 fiif [ 1 ] &then sleep 10 fiwait
it takes 30 seconds to run
$ time . test.sh [3] Done [ 1 ][3] Done [ 1 ][3] Done [ 1 ]real 0m30.015suser 0m0.003ssys 0m0.012s
and you see that the backgrounded task is [ 1 ]
, not sleep
. Note that is is meaningless as explained by @chepner.
Now the other case:
#!/bin/bashif [ 1 ] then sleep 10 &fiif [ 1 ] then sleep 10 &fiif [ 1 ] then sleep 10 &fiwait
gives:
[2] Done sleep 10[3] Done sleep 10[4]- Done sleep 10real 0m10.197suser 0m0.003ssys 0m0.014s
It only takes 10 seconds ; all the sleeps
are simultaneous as they are being backgrounded.
Last option as described by @DigitalTrauma:
#!/bin/bashif [ 1 ] then sleep 10 fi &if [ 1 ]then sleep 10 fi &if [ 1 ] then sleep 10fi &wait
Then the whole if
statement is backgrounded, i.e. both the evaluation of exprN
and of taskN
[3] Done if [ 1 ]; then sleep 10;fi[4] Done if [ 1 ]; then sleep 10;fi[5] Done if [ 1 ]; then sleep 10;fireal 0m10.017suser 0m0.003ssys 0m0.013s
giving the expected 10 seconds running time
Compare
if falsethen echo "condition true"fi
with
if false &then echo "condition ... true?"fi
A command terminated by &
exits immediately with status 0, so the if
branch is taken regardless of what the background process eventually returns. It doesn't make sense to put a command that unconditionally succeeds in the command list of an if
statement. You have to let it complete so the body can be correctly (conditionally) executed.