代码之家  ›  专栏  ›  技术社区  ›  Osama Al-Maadeed

如何让Perl等待在后台使用system()启动的子进程?

  •  10
  • Osama Al-Maadeed  · 技术社区  · 17 年前

    for $p (@a){
        system("/path/to/file.sh $p&");
    }
    

    将代码转换为使用fork()会很困难。难道没有更简单的方法吗?

    3 回复  |  直到 12 年前
        1
  •  17
  •   Dave    17 年前

    my @a = (1, 2, 3);
    for my $p (@a) {
       my $pid = fork();
       if ($pid == -1) {
           die;
       } elsif ($pid == 0) {
          exec '/bin/sleep', $p or die;
       }
    }
    while (wait() != -1) {}
    print "Done\n";
    
        2
  •  14
  •   Chas. Owens    17 年前

    您将不得不更改某些内容,将代码更改为使用fork可能更简单,但是如果您坚决反对使用fork,您可以使用一个包装器shell脚本,该脚本在完成时会触及文件,然后让您的Perl代码检查文件是否存在。

    #!/bin/bash
    
    $*
    
    touch /tmp/$2.$PPID
    

    您的Perl代码如下所示:

    for my $p (@a){
        system("/path/to/wrapper.sh /path/to/file.sh $p &");
    }
    while (@a) {
        delete $a[0] if -f "/tmp/$a[0].$$";
    }
    

    但我认为分叉代码更安全、更清晰:

    my @pids;
    for my $p (@a) {
        die "could not fork" unless defined(my $pid = fork);\
        unless ($pid) { #child execs
            exec "/path/to/file.sh", $p;
            die "exec of file.sh failed";
        }
        push @pids, $pid; #parent stores children's pids
    }
    
    #wait for all children to finish
    for my $pid (@pids) {
        waitpid $pid, 0;
    }
    
        3
  •  9
  •   darch    17 年前

    转换为fork()可能很困难,但它是正确的工具。system()是一个阻塞调用;通过执行shell并告诉它在后台运行脚本,可以获得非阻塞行为。这意味着Perl不知道子级的PID可能是什么,这意味着您的脚本不知道等待什么。

    您可以尝试将PID传递给Perl脚本,但这很快就会失控。使用fork()。