我正在寻找一种方法来启动几个与DCL并行运行的后台进程。我想等待他们全部完成,并知道他们是否都成功或至少一次失败。这就像使用&并在bash中等待。
我读了spawn / nowait的文档,但是在产生多个子进程后我没有看到等待的方法。我想我可以让subproceses在退出时写入文件并在睡眠循环中检查来自父文件的文件?但是有更好/内置的方式吗?
答案 0 :(得分:4)
两种可靠的手段是:
如果您submit
将它们作为批处理作业,则可以使用synchronize
命令依次等待每个作业。
使用run/detach
启动流程可让您指定/mailbox
来接收终止消息。
子流程略有不同。一种方法是共享逻辑名称表,并使每个子进程相应地更新其状态。无法保证会报告异常终止。
如果您愿意做一些额外的工作,可以创建几个小应用程序来使用锁管理器或公共事件标志集群来传达状态更新。
答案 1 :(得分:1)
$ 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******
答案 2 :(得分:0)
正如所指出的,SYNCHRONIZE是最强大的方法。
一个草率但通常是适当的方法是首先使用spawn / nowait创建最短期任务,然后生成/等待预期最后运行的任务。
要收紧它,您可以输入一个轮询循环,使用F $ CONTEXT查看MASTER_PID = your-pid计算返回的F $ PID值的数量,可选F $ GETJPI
例如,Hackish方法是尝试重用进程名称,或者尝试打开一个不允许共享的进程日志文件,只有在进程消失后才能使用,或者解析SHOW PROC / SUB输出。也许你可以创建一个简单的shell程序来执行一堆(lib $)生成并使用完成AST来确定何时完成所有这些?
您可能还想查看CRTL函数waitpid。
HTH, 海因。
答案 3 :(得分:0)
您可以随时在Perl中打开管道,然后使用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
替换要等待“wait 00:00:05”命令的实际DCL命令。这里文件句柄F是一个只写的文件句柄,连接到子项的stdin / SYS $ INPUT。如果孩子对SYS $ INPUT进行任何阻塞读取,则父母将需要写出预期的内容或孩子将挂起。或者你可以把管道字符|在命令的最后,然后F将是一个连接到子的stdout / SYS $ OUTPUT的只读文件句柄。如果等待多个孩子,你可能需要使用wait()而不是waitpid()。
答案 4 :(得分:0)
简单地轮询suprocess计数。 " PRCCNT" f $ getjpi的参数是你需要的值,名称可能会误导(作为总进程作业计数),它是子进程计数。 这是一个" oneliner" (当然,"由kB&#34支付;可能将其分成半页):
$ spawn/nowait command1
$ spawn/nowait command2
...
$waitall: if f$getjpi("","PRCCNT").gt.0 then pipe wait 0::.5 ; goto waitall
...
将轮询间隔设置为合理值,适用于命令执行时间,当然,0.5秒不是通用值。