在perl中等待subprocess

我在捕获subprocess的返回状态时遇到问题。 下面是我的代码的简化版本。

use Modern::Perl; use POSIX; use AnyEvent; my @jobs = (1, 7, 3, 9 , 4 , 2); my %pid; my %running; my $t = AE::timer 0, 5, sub{ while(scalar( keys %running < 3) && scalar (@jobs)){ my $job = shift @jobs; $running{$job}=1; $pid{$job} = run($job); } for(keys %running){ delete $running{$_} unless check($pid{$_},$_); } exit unless scalar keys %running; }; AnyEvent->condvar->recv; sub func_to_run{ my $id = shift; close STDOUT; open STDOUT, ">>$id.log"; exec '/bin/sleep', $id; } sub run{ my $id = shift; print "starting job $id\n"; my $pid = fork(); return $pid if $pid; func_to_run($id); } sub check{ my ($pid,$id) = @_; my $result = waitpid($pid, WNOHANG); { if ($result == $pid) { my $rc = $? >> 8; print "Job $id finished with code $rc\n"; return 0; } elsif ($result == -1 and $! == ECHILD) { print "Job $id finished running, not sure if it was sucessfull\n"; return 0; } elsif ($result == 0) { return 1; } redo; } } 

OUTPUT:

 starting job 1 starting job 7 starting job 3 Job 1 finished running, not sure if it was sucessfull Job 3 finished running, not sure if it was sucessfull starting job 9 starting job 4 Job 7 finished running, not sure if it was sucessfull starting job 2 Job 4 finished running, not sure if it was sucessfull Job 9 finished running, not sure if it was sucessfull Job 2 finished running, not sure if it was sucessfull 

为什么waitpid()返回-1而不是返回状态?

编辑:我改变了系统+退出到执行。 这正是我原来所做的。 我的目标是能够发信号给孩子的过程,我并不认为可以用系统来完成。

 kill($pid,'HUP'); 

编辑2:可以有几个subprocess一次运行,这是从一个AE ::定时器模块调用。 我想知道的是为什么我从waitpid()中得到-1,这表明孩子已经被收割了。

编辑3:我已经改变了代码到一个完整的工作示例与我得到的输出

我检查了你的代码实际上是用linux上的strace命令做的。 以下是您在完成一个sleep命令后看到的内容:

  $ strace -f perl test.pl
 ...
 [pid 4891] nanosleep({1,0},NULL)= 0
 [pid 4891] close(1)= 0
 [pid 4891] close(2)= 0
 [pid 4891] exit_group(0)=?
 ++ [pid 4891] +++退出0 +++
  2061530,64,4990)= -1 EINTR(中断的系统调用)
 --- SIGCHLD {si_signo = SIGCHLD,si_code = CLD_EXITED,si_pid = 4891,si_status = 0,si_utime = 0,si_stime = 0} ---
写(4,“\ 1 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0”,8)= 8
 rt_sigreturn()= -1 EINTR(中断的系统调用)
 clock_gettime(CLOCK_MONOTONIC,{97657,317300660})= 0
 clock_gettime(CLOCK_MONOTONIC,{97657,317371410})= 0
 epoll_wait(3,{{EPOLLIN,{u32 = 4,u64 = 4294967300}}},64,3987)= 1
 clock_gettime(CLOCK_MONOTONIC,{97657,317493076})= 0
读取(4,“\ 1 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0 \ 0”,8)= 8
 wait4(-1,[{WIFEXITED(s)&& WEXITSTATUS(s)== 0}],WNOHANG | WSTOPPED | WCONTINUED,NULL)= 4891
 wait4(-1,0x7fff8f7bc42c,WNOHANG | WSTOPPED | WCONTINUED,NULL)= -1 ECHILD(无子进程)
 clock_gettime(CLOCK_MONOTONIC,{97657,317738921})= 0
 epoll_wait(3,{},64,3986)= 0
 clock_gettime(CLOCK_MONOTONIC,{97661,304667812})= 0
 clock_gettime(CLOCK_MONOTONIC,{97661,304719985})= 0
 epoll_wait(3,{},64,1)= 0
 ... 

开始[pid 4891]的行来自sleep命令,其余的来自脚本。 您可以看到脚本正在调用wait4()系统调用并返回睡眠进程的PID – 大概是脚本正在使用的事件循环的一部分。 这就是为什么你从waitpid()调用-1的原因 – 子进程已经被获得了。

顺便说一句,AnyEvent文档有一个部分( 儿童进程监视 )关注儿童进程和检查他们的返回代码。 从文档:

 my $done = AnyEvent->condvar; my $pid = fork or exit 5; my $w = AnyEvent->child ( pid => $pid, cb => sub { my ($pid, $status) = @_; warn "pid $pid exited with status $status"; $done->send; }, ); # do something else, then wait for process exit $done->recv; 

关于使用system()exec()来产生进程,你使用exec()是正确的。 这是因为system()创建一个子进程来执行它的命令,而exec()用这个命令替换当前进程。 这意味着system()中的$pid将引用分叉的Perl脚本,而不是Perl脚本运行的命令。