2strange
2strange

Reputation: 33

identify the end timestamp of the parallel process triggered in shell

process p3 completes first than the other two but the process is waiting till the process p1 is completed and the end_time is the same for all the 3 processes. But i want to get the timestamp of p3 process as soon as it is completed and the same with p2 and p1. Thanks in advance

p1_start_time=`date "+%Y-%m-%d %H:%M:%S"`
sleep 100 &
p1=$!

p2_start_time=`date "+%Y-%m-%d %H:%M:%S"`
sleep 60 &
p2=$!

p3_start_time=`date "+%Y-%m-%d %H:%M:%S"`
sleep 20 &
p3=$!


$(wait $p1 ; rc=$? ; p1_end_time=`date "+%Y-%m-%d %H:%M:%S"`) &
$(wait $p2 ; rc=$? ; p2_end_time=`date "+%Y-%m-%d %H:%M:%S"`) &
$(wait $p3 ; rc=$? ; p3_end_time=`date "+%Y-%m-%d %H:%M:%S"`) &

wait

echo "out of wait"

echo "$p1_end_time"
echo "$p2_end_time"
echo "$p3_end_time"

Upvotes: 1

Views: 152

Answers (1)

markp-fuso
markp-fuso

Reputation: 35116

The 3x backgrounded (aka 'child') pids (p1 / p2 / p3) are available to the main/calling process (aka the 'parent'). Only the 'parent' process can use the wait command to wait for the 'child' processes to complete.

For each of the $(wait $p ...) constructs a separate OS-level process is spawned and while you can pass the background pids to these new processes, said processes are not the 'parent' of said background pids; the net effect is the three wait $p# calls are (effectively) ignored and the 3x p#_end_time variables are immediately populated with the current date/time. But, keep in mind the 3x p#_end_time variables are being assigned within separate sub-processes which means when said processes exit the associated p#_end_time variables are discarded (ie, the values are not passed back 'up' to the main/calling process).

Also keep in mind that when a process is put in the background it is executed asynchronously, which means a separate OS-level process is spawned. In order to pass data back 'up' to the main/calling process (eg, in this case the end time of the background processes) it becomes necessary to implement some sort of inter-process communications or use an intermediate storage option for sharing data (eg, pipe, file, database table, queuing system, etc).

One idea for capturing the separate end times:

  • upon exiting the sleep, write the current date/time to a temp file; this is how we'll pass data 'up' from the background (aka child) processes to the parent process
  • while not an issue for this scenario, we'll have each child process write to a separate temp file to alleviate any issues with race conditions and scrambling of data when multiple processes write to the same file at the same time
  • for this answer I'm going to use a couple arrays to store the start and end times; this allows for a little less coding by using a couple loops
  • if the OP needs to use explicit variables for each start/end pair then the loops can be replaced with individual calls using the explicit variable names

One implementation:

unset pstart pend                                 # delete any variables with these names
pstart=()                                         # init arrays for
pend=()                                           # start and end times

outdir=$(mktemp -d)                               # create temp directory for storing temp files containing end date/times

stime=100                                         # initial sleep time

for i in {1..3}                                   # we'll do 3x passes through the loop
do
    pstart["${i}"]=$(date "+%Y-%m-%d %H:%M:%S")   # save the start date/time

    # kick off sleep + 'echo date/time > temp file' in the background; each sub-process will have a different OS-level pid == BASHPID

    (sleep "${stime}"; echo "${i} "$(date "+%Y-%m-%d %H:%M:%S") > "${outdir}/${BASHPID}") &

    stime=$((stime-40))                           # OP's example just happens to use times that are 40 seconds apart
done

wait                                              # wait for all background processes to complete

# load our end times into the pend array

while read -r i dt
do
    pend["${i}"]="${dt}"
done < <(cat "${outdir}"/[0-9]*)

# display start/end times for our processes (OP can reformat as needed)

for i in {1..3}
do
    echo "process #${i} start/end times: ${pstart[${i}]} - ${pend[${i}]}"
done

# get rid of the temp directory and files

'rm' -rf "${outdir}" >/dev/null 2>&1

The output from a sample run:

process #1 start/end times: 2020-10-14 22:49:28 - 2020-10-14 22:51:08
process #2 start/end times: 2020-10-14 22:49:28 - 2020-10-14 22:50:28
process #3 start/end times: 2020-10-14 22:49:28 - 2020-10-14 22:49:48

Upvotes: 2

Related Questions