ForkManager SIGINT 仅杀死 fork 中的当前进程

ForkManager SIGINT only kills current process in fork

我希望在终止使用 ForkManager 的 perl 进程时终止所有子进程。在下面的代码中,如果我 运行 它并按下 ctrl+c 而睡眠线是 运行ning,睡眠进程被终止,但是 print 行在脚本结束之前全部同时执行。理想情况下,我希望中断立即停止所有执行。我能做什么?

#!/usr/bin/perl -w
use Parallel::ForkManager;

main {
    my $fork1 = new Parallel::ForkManager(8);
    while (1) {
        $fork1->start and next;
        system("sleep 15s");
        print "Still going!"
        $fork1->finish;
    }
    fork1->wait_all_children;
}

根据perldoc systemsystem实际上忽略了SIGINT和SIGQUIT:

Since SIGINT and SIGQUIT are ignored during the execution of system, if you expect your program to terminate on receipt of these signals you will need to arrange to do so yourself based on the return value.

因此,如果您希望进程在 system 调用期间收到 SIGINT 时停止执行,则需要自己实现该逻辑:

#!/usr/bin/perl -w
use Parallel::ForkManager;

main {
   my $fork1 = new Parallel::ForkManager(8);
   while (1) {
      $fork1->start and next;
      print "Sleeping...";
      system("sleep 15s") == 0 or exit($?);
      print "Still going!";
      $fork1->finish;
   }
   fork1->wait_all_children;
}

或者更合理的方法是使用 Perl 内置 sleep

#!/usr/bin/perl -w
use Parallel::ForkManager;

main {
   my $fork1 = new Parallel::ForkManager(8);
   while (1) {
      $fork1->start and next;
      print "Sleeping...";
      sleep 15;
      print "Still going!";
      $fork1->finish;
   }
   fork1->wait_all_children;
}

首先 - 使用 system 意味着你可能会发生一些奇怪的事情,因为......然后你允许你调用的任何东西自己处理信号。

这可能是你的问题。

然而,除此之外,您可以使用 perl 做的是配置信号处理程序 - 如果此进程收到信号,该怎么办。默认情况下 - 信号设置为 'exit' 或 'ignore'.

您可以通过 print Dumper \%SIG;

查看当前的内容

不过,我认为解决您问题的最简单方法是设置一个处理程序来捕获 SIGINT,然后将 kill 发送到您当前的进程组。

The behavior of kill when a PROCESS number is zero or negative depends on the operating system. For example, on POSIX-conforming systems, zero will signal the current process group, -1 will signal all processes, and any other negative PROCESS number will act as a negative signal number and kill the entire process group specified.

$SIG{'INT'} = sub { 
    kill ( 'TERM', -$$ );
};