Need help on Assigning a Array variable from Background Functions

I have a question on how can I assign a output of a function to a variable which is executed in background.

Here is my example

$ cat sample_program.sh
#!/bin/ksh

exec_func () {
sleep 1
v=`expr $1 + 100`
print $v
}

export OUT_ARR
date
for i in 1 2
do
OUT_ARR[$i]=`exec_func $i` &
done

wait
date

print ${OUT_ARR[@]}

$ ksh -x sample_program.sh
+ export OUT_ARR
+ date
Tue Jul 22 21:31:39 PDT 2014
+ exec_func 1
+ sleep 1
+ exec_func 2
+ sleep 1
+ wait
+ expr 1 + 100
+ v=101
+ print 101
+ OUT_ARR[1]=101
+ expr 2 + 100
+ v=102
+ print 102
+ OUT_ARR[2]=102
+ date
Tue Jul 22 21:31:40 PDT 2014
+ print

$

From the above program and output you can see that finally I was not able to print the value of the array variable OUT_ARR.

I am able to do the same if I am not executing the function in background.
See below execution

$ cat sample_program.sh
#!/bin/ksh

exec_func () {
sleep 1
v=`expr $1 + 100`
print $v
}

export OUT_ARR
date
for i in 1 2
do
OUT_ARR[$i]=`exec_func $i`
done

wait
date

print ${OUT_ARR[@]}

$ ksh -x sample_program.sh
+ export OUT_ARR
+ date
Tue Jul 22 21:33:29 PDT 2014
+ exec_func 1
+ sleep 1
+ expr 1 + 100
+ v=101
+ print 101
+ OUT_ARR[1]=101
+ exec_func 2
+ sleep 1
+ expr 2 + 100
+ v=102
+ print 102
+ OUT_ARR[2]=102
+ wait
+ date
Tue Jul 22 21:33:31 PDT 2014
+ print 101 102
101 102
$

See this time I am able to see the output but the time taken is more. I want to execute the functions in Background so that the time taken to complete the loop is less.

Any help is greatly appreciated.

Thanks in Advance!

Mohan Kumar CS

---------- Post updated at 11:54 PM ---------- Previous update was at 11:40 PM ----------

I guess i found the answer.

i just changed the way i pushed the function execution within the back quotes.

OUT_ARR[$i]=`exec_func $i &`

This made the magic
Here is the output

$ cat sample_program.sh
#!/bin/ksh

exec_func () {
sleep 1
v=`expr $1 + 100`
print $v
}

export OUT_ARR
date
for i in 1 2
do
OUT_ARR[$i]=`exec_func $i &`
done

wait
date

print ${OUT_ARR[@]}

$ ksh -x sample_program.sh
+ export OUT_ARR
+ date
Tue Jul 22 21:52:59 PDT 2014
+ exec_func 1
+ sleep 1
+ expr 1 + 100
+ v=101
+ print 101
+ OUT_ARR[1]=101
+ exec_func 2
+ sleep 1
+ expr 2 + 100
+ v=102
+ print 102
+ OUT_ARR[2]=102
+ wait
+ date
Tue Jul 22 21:53:01 PDT 2014
+ print 101 102
101 102
$

Starting a pipeline in the background creates a new shell execution environment. Variables set in that new shell execution environment are not visible in the parent (foreground) shell execution environment.

There are several ways things like this can be done. One way that works if the values you want to produce in the background are always less than or equal to 255, is:

#!/bin/ksh
exec_func() {
	sleep 1
	printf 'exec_func exiting with %d\n' "$(( $1 + 100 ))"
	exit $(( $1 + 100 ))
}

date
for i in 1 2
do	exec_func $i&
	pid=$!
done
for i in 1 2
do	wait ${pid}
	OUT_ARR=$?
done
date
print ${OUT_ARR[@]}

which produces the output:

Tue Jul 22 22:27:03 PDT 2014
exec_func exiting with 102
exec_func exiting with 101
Tue Jul 22 22:27:04 PDT 2014
101 102

but the order of the two lines in red may vary from run to run (and may be intermixed on a multi-processor system).

1 Like