Question

I am looking for a way to launch several background processes to run in parallel with DCL. I would want to wait for them all to complete and know whether they all succeeded or at least one failed. This would be like using & and wait in bash.

I read the docs for spawn/nowait but I don't see a way to wait after spawning multiple subprocesses. I suppose I could have the subproceses write to a file when they exit and check the file from the parent in a sleep-loop? But is there a better/built-in way?

Was it helpful?

Solution

Two reliable means are:

If you submit them as batch jobs you can use the synchronize command to wait on each in turn.

Using run/detach to start the processes allows you to specify a /mailbox to receive the termination message.

Subprocesses are a little different. One approach is to share a logical name table and have each subprocess update its status accordingly. There is no guarantee that an abnormal termination will be reported.

If you are willing to do some extra work you can create a couple of small applications to use either the lock manager or a common event flag cluster to communicate status updates.

OTHER TIPS

$   BKGVFY = F$VERIFY(0)  !******Start of BACKGROUND******
$!*DOC+
$!*
$!* Procedure    : BACKGROUND.COM
$!*
$!*   Abstract   : Invoke Commands in Background
$!*
$!*   Prototype  : @MYDCL:BACKGROUND "RUN PROG1" "@COMFIL" "RUN PROG2"
$!*
$!*   Description: This utility is used to run background spawned jobs. It
$!*                will return control after all of the jobs have run.
$!*
$!*          Note: Requires GRPNAM or SYSNAM Privilege
$!*
$!* Parameters   : P1 = Background Command (Required)
$!*                P2 = Background Command (Optional)
$!*                P3 = Background Command (Optional)
$!*                P4 = Background Command (Optional)
$!*                P5 = Background Command (Optional)
$!*                P6 = Background Command (Optional)
$!*                P7 = Background Command (Optional)
$!*                P8 = Background Command (Optional)
$!*
$!* Change Control Log:
$!*
$!*        Who         Date      Description
$!*  --------------- ----------  -----------
$!*  Scott Kelbell   02/16/2010  Initial version
$!*
$!*DOC-
$   !
$   ! VALIDATION
$   !
$   IF P1 .EQS. "" .OR. P1 .EQS. "HELP" .OR. P1 .EQS. "?" THEN EXIT
$   IF F$PRIVILEGE("GRPNAM")
$   THEN
$     BKGPRIV = "GROUP"
$   ELSE
$     IF F$PRIVILEGE("SYSNAM")
$     THEN
$       BKGPRIV = "SYSTEM"
$     ELSE
$       WRITE SYS$OUTPUT "%BACKGROUND-F-IPRV, insufficient priv (GRPNAM)"
$       EXIT
$     ENDIF
$   ENDIF
$   !
$   ! INITIALIZATION
$   !
$   BKGN     = "BKG" + F$UNIQUE()   ! Background Logical Prefix
$   BKGFIL   = "SYS$LOGIN:" + BKGN  ! Background File Prefix
$   BKGCNT   = 0                    ! Parameter Counter
$   !
$   ! MAINLINE
$   !
$ LOOP:
$   IF BKGCNT .EQ. 8 THEN GOTO LOOP_WAIT
$   BKGCNT = BKGCNT + 1
$   IF P'BKGCNT' .NES. ""                           ! For each parameter
$   THEN
$     BKGLOG = BKGFIL + ".LOG_" + F$STRING(BKGCNT)
$     CREATE/FDL=NL: 'BKGFIL'.TMP_'BKGCNT' ! Create the command procedure
$     OPEN/APPEND 'BKGN' 'BKGFIL'.TMP_'BKGCNT'
$     BKGLNM = BKGN + "_" + F$STRING(BKGCNT)
$     WRITE 'BKGN' "$ SET VERIFY"
$     WRITE 'BKGN' "$ ! Background Job #", P'BKGCNT', " ", F$TIME()
$     WRITE 'BKGN' "$ SET NOON"
$     WRITE 'BKGN' "$ DEFINE/NOLOG/", BKGPRIV, " ", BKGLNM, " RUNNING"
$     WRITE 'BKGN' "$ ", P'BKGCNT'
$     WRITE 'BKGN' "$ DEFINE/NOLOG/", BKGPRIV, " ", BKGLNM, " FINISHED"
$     WRITE 'BKGN' "$ EXIT ! End of Background Job"
$     CLOSE 'BKGN'
$     DEFINE/'BKGPRIV' 'BKGN'_'BKGCNT' INITIALIZED
$     SPAWN/NOWAIT/OUTPUT='BKGLOG'/NOLOG @'BKGFIL'.TMP_'BKGCNT'
$     GOTO LOOP
$   ENDIF
$   BKGCNT = BKGCNT - 1
$   !
$   ! WAIT LOGIC
$   !
$ LOOP_WAIT:
$   CURLOG = BKGN + "_" + F$STRING(BKGCNT)
$   IF F$TRNLNM("''CURLOG'") .NES. "FINISHED"
$   THEN
$     WAIT 00:00:05
$     GOTO LOOP_WAIT
$   ENDIF
$   DEASSIGN/'BKGPRIV' 'BKGN'_'BKGCNT'
$   DELETE/NOLOG/NOCONFIRM 'BKGFIL'.TMP_'BKGCNT';*
$   BKGCNT = BKGCNT - 1
$   IF BKGCNT .GT. 0 THEN GOTO LOOP_WAIT
$   !
$   ! EXIT LOGIC
$   !
$ EXIT:
$   BKGVFY = F$VERIFY(BKGVFY) !******End of BACKGROUND******

As pointed out, SYNCHRONIZE is the most robust method.

One sloppy, but often adequate method is to create the shortest lived tasks first with spawn/nowait and spawn/wait the task expected to run last.

To tighten that up you can enter a polling loop with F$CONTEXT looking of MASTER_PID = your-pid counting the number of returned F$PID values, with optional F$GETJPI

Hackish ways are for example to try re-use a process name, or to try open a process log file not allowing sharing which will only work once the process is gone, or parse SHOW PROC/SUB output.

Maybe you can create a simple shell program to perform a bunch of (lib$)spawns and use the completion AST to figure out when all are done?

You may also want to check out the CRTL function waitpid.

hth, Hein.

You can always do a piped open in Perl and then wait for it with waitpid:

$ perl -e "my $pid = open F, '| wait 00:00:05'; print qq/waiting for $pid\n/; waitpid($pid, 0); close F;"
waiting for 6233

Substitute the actual DCL command you want to wait on for the "wait 00:00:05" command. Here the filehandle F is a write-only filehandle hooked up to the child's stdin/SYS$INPUT. If the child does any blocking reads on SYS$INPUT, the parent will need to write whatever it is expecting or the child will hang. Or you can put the pipe character | at the end of the command and then F will be a read-only filehandle connected to the child's stdout/SYS$OUTPUT. If waiting on more than one child, you may need to use wait() rather than waitpid().

Simply poll the suprocess count. The "PRCCNT" parameter of f$getjpi is the value you need, the name may be misleading (as total process job count), it is subprocess count. That is a "oneliner" (of course, a "payd by kB" may split it to half page):

$ spawn/nowait command1
$ spawn/nowait command2
...
$waitall: if f$getjpi("","PRCCNT").gt.0 then pipe wait 0::.5 ; goto waitall
...

Set the polling interval to sensible value, appropiate for the command execution times, of course, 0.5 sec is not a universal one.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top