首页 > 解决方案 > 按下控制 c 时停止 bsub 作业的 Perl 脚本

问题描述

我正在运行一个内部启动 bsub 作业的 perl 脚本。当我基于组 id 运行 perl 脚本时,当我在 unix 终端中按下控制 c 时,我想终止此 perl 脚本启动的所有作业。

请指教。

感谢和问候阿姆鲁塔


编辑:从评论中复制的代码

my $command = "bsub -q normal -g GROUPID <command>";

system($command); 

标签: perlcontrol-c

解决方案


尝试从 Ctrl-C 的信号处理程序SIGTERM通过kill发送到进程组

$SIG{INT} = sub { kill 15, -$gpid };  # $gpid used in bsub command

这是否会奏效,以及如何可靠,取决于这些工作是什么和做什么的许多细节。

下面是一个进程如何(在不知不觉中)躲避子弹的示例,其中子进程更改了其进程组 ID。它这样做是为了演示向该组发送信号,但这也表明在向该组发送信号时存在漏洞。

一个例子

use warnings;
use strict;
use feature 'say';

my $pid;

$SIG{INT} = sub { 
    say "Got $_[0]. Send TERM to process group with $pid"; 
    kill 15, -$pid;
}; 

$pid = fork // die "Can't fork: $!";

if ($pid == 0) {
    $SIG{INT} = 'IGNORE';
    setpgrp 0, $$;
    say "\tChild's process group: ", getpgrp;
    sleep 10; 
    say "\tkid done"; 
    exit;
}; 

say "Parent $$ started $pid";

sleep 5; 
sleep 3;   # return to sleep after signal is handled

say "done";

kill被发送到否定的 PID(或带有否定信号)时,它会进入该进程组。在这里,我使用孩子的$pid(要分配的)并在孩子中将其组 id 设置为那个($$)。

由于分叉的进程继承了处理程序,因此信号也必须在子进程中处理。

几秒钟后按下Ctrl-C,输出为

父 10450 开始 10451
        子进程组:10451
^C得到 INT。发送 TERM 到组 10451
完毕

wheredone在前一次打印后 3 秒打印。kid done永远不会到来。

如果您希望父级也终止,exit请在信号处理程序中添加一个或这样的。

如前所述,这可能会失败,因为孩子可以简单地更改其组。一种更可靠的方法是对可能被触发的作业进行编目,然后在运行时找到它们的 PID,从而终止它们。一个有用的工具是Proc::ProcessTable这篇文章这篇文章中有一些追捕过程的例子。


推荐阅读