如果父节点拦截SIGINT,则等待子节点完成

时间:2015-11-04 10:02:59

标签: perl fork

我有一个带有多个子进程的perl脚本(使用fork()创建)。每个孩子睡觉然后做一些处理(几个系统()调用)。在Windows下,当我按下Ctrl + C时,我看到信号被捕获,然后脚本等待孩子完成并在此退出之后。我想在linux中复制这种行为(捕获sigint,让孩子完成并退出主脚本/进程)。

如何在杀死父母之前等待所有孩子完成?是否可以退出主脚本/杀死父级,但让孩子在后台完成?

我找到Child process receives parent's SIGINT,似乎SIGINT传播给子节点(进程组),所以为了避免这种情况,我必须将子节点设置在不同的进程组中。

$SIG{'INT'} = sub {
    print "Caught Ctrl+C\n";
    die "Stopping...";
};

++$|;

print "Start\n";
for($i=0; $i < 500; $i++) {
    sleep 3;
    $childPid = fork(); #fork a process
    if($childPid == 0){
        print "Child $i...\n";
        sleep 10;
        system("echo finishing");
        print "Exit child $i\n";
        exit;
    }
}

我也尝试将其包含在SIGINT处理块中,但for循环没有暂停,因此创建了新的子进程,父进程不会死。

# I used my $parentPid = $$; (before  the for loop) to get the parent pid.

if ($$ = $parentPid){
    foreach $var (@pids) {
        $pid = waitpid($var ,0);
    }  

修改

尝试将子SIGINT处理程序设置为IGNORE,它按预期工作。在父处理程序中我做:

$SIG{'INT'} = sub {
  print "Caught Ctrl+C by $$\n";
  # while($result != -1){
      # $result = wait();
  #}
    die "Stopping...";
}; 

a)如果包含注释行,脚本会等待孩子完成然后退出。

b)但是,如果我评论“等待”行,我认为它的工作原理如下

  1. 脚本退出,父进程终止
  2. 孩子们继续在后台跑步并在退出前按预期显示“退出孩子”消息。
  3. 我理解a)案例,但b)案例如何运作,请解释为什么这不会产生僵尸进程?

1 个答案:

答案 0 :(得分:0)

  

在Windows下,当我按下Ctrl + C时,我看到信号被捕获,然后脚本等待孩子完成并在此之后退出。

我认为这是psuedo-fork实现的副作用。

  

如何在杀死父母之前等待所有孩子完成?

最简单的方法是忽略子项中的SIGINT和父项wait处理程序中的waitpid / SIGINT

  

我也尝试将其包含在SIGINT处理块中,但for循环没有暂停,因此创建了新的子进程并且父进程没有死。

我认为你的意思是$$ == $parentPid(比较而不是作业)。此外,如果您还等待所有孩子,那么指定您正在等待的孩子并不是真的有用。