带子进程的 Perl 警报

发布于 2024-12-20 09:15:43 字数 924 浏览 0 评论 0原文

我有一个 perl 脚本,它运行一系列批处理脚本以进行回归测试。我想在批处理脚本上实现超时。我目前有以下代码。

    my $pid = open CMD, "$cmd 2>&1 |";
    eval {
               # setup the alarm
               local $SIG{ALRM} = sub { die "alarm\n" };
               # alarm on the timeout
               alarm $MAX_TIMEOUT;
               log_output("setting alarm to $MAX_TIMEOUT\n");

               # run our exe
               while( <CMD> ) {
                       $$out_ref .= $_;
               }
               $timeRemaining = alarm 0;
            };
            if ($@) {
                    #catch the alarm, kill the executable
            }

问题是,无论我将最大超时设置为多少,警报都不会触发。我尝试过使用 Perl::Unsafe::Signals 但这没有帮助。

如果我希望能够捕获批处理脚本的输出,这是执行批处理脚本的最佳方法吗?是否有另一种方法可以做同样的事情,允许我使用警报,或者除了警报之外还有其他方法来使程序超时?

我已经构建了一个测试脚本来确认警报适用于我的 perl 和 windows 版本,但当我运行这样的命令时它不起作用。

我在 Windows 7 x64 上使用 activeperl 5.10.1 运行它。

I have a perl script that runs a series of batch scripts for regression testing. I want to implement a timeout on the batch scripts. I currently have the following code.

    my $pid = open CMD, "$cmd 2>&1 |";
    eval {
               # setup the alarm
               local $SIG{ALRM} = sub { die "alarm\n" };
               # alarm on the timeout
               alarm $MAX_TIMEOUT;
               log_output("setting alarm to $MAX_TIMEOUT\n");

               # run our exe
               while( <CMD> ) {
                       $out_ref .= $_;
               }
               $timeRemaining = alarm 0;
            };
            if ($@) {
                    #catch the alarm, kill the executable
            }

The problem is that no matter what I set the max timeout to, the alarm is never tripped. I've tried using Perl::Unsafe::Signals but that did not help.

Is this the best way to execute the batch scripts if I want to be able to capture their output? Is there another way that would do the same thing that would allow me to use alarms, or is there another method besides alarms to timeout the program?

I have built a test script to confirm that alarm works on with my perl and windows version, but it does not work when I run a command like this.

I'm running this with activeperl 5.10.1 on windows 7 x64.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

梦里梦着梦中梦 2024-12-27 09:15:43

很难判断 alarm 何时起作用,系统调用何时会或不会被 SIGALRM 中断,相同的代码在不同操作系统上的行为可能会有所不同,等等。

如果你的工作超时,你想终止你已经启动的子进程。这是穷人警报的一个很好的用例:

my $pid = open CMD, "$cmd 2>&1 |";
my $time = $MAX_TIMEOUT;

my $poor_mans_alarm = "sleep 1,kill(0,$pid)||exit for 1..$time;kill -9,$pid";
if (fork() == 0) {
    exec($^X, "-e", $poor_mans_alarm);
    die "Poor man's alarm failed to start";  # shouldn't get here
}
# on Windows, instead of  fork+exec, you can say
#    system 1, qq[$^X -e "$poor_mans_alarm"]


...

穷人的警报在单独的进程中运行。每秒,它都会检查标识符为 $pid 的进程是否仍然存在。如果进程不存在,则警报进程退出。如果进程在 $time 秒后仍然存在,它会向进程发送一个终止信号(我使用 9 使其不可捕获,使用 -9 取出整个子进程树,您的需求可能会有所不同) 。

exec 实际上可能不是必需的。我使用它是因为我还使用这个习惯用法来监视可能比启动它们的 Perl 脚本寿命更长的进程。因为这个问题不会出现这种情况,你可以跳过 exec 调用并

if (fork() == 0) {
    for (1..$time) { sleep 1; kill(0,$pid) || exit }
    kill -9, $pid;
    exit;
}

改为说。)

It's hard to tell when alarm will work, when a system call will and won't get interrupted by a SIGALRM, how the same code might behave differently on different operating systems, etc.

If your job times out, you want to kill the subprocess you have started. This is a good use case for the poor man's alarm:

my $pid = open CMD, "$cmd 2>&1 |";
my $time = $MAX_TIMEOUT;

my $poor_mans_alarm = "sleep 1,kill(0,$pid)||exit for 1..$time;kill -9,$pid";
if (fork() == 0) {
    exec($^X, "-e", $poor_mans_alarm);
    die "Poor man's alarm failed to start";  # shouldn't get here
}
# on Windows, instead of  fork+exec, you can say
#    system 1, qq[$^X -e "$poor_mans_alarm"]


...

The poor man's alarm runs in a separate process. Every second, it checks whether the process with identifier $pid is still alive. If the process isn't alive, the alarm process exits. If the process is still alive after $time seconds, it sends a kill signal to the process (I used 9 to make it untrappable and -9 to take out the whole subprocess tree, your needs may vary).

(The exec actually may not be necessary. I use it because I also use this idiom to monitor processes that might outlive the Perl script that launched them. Since that wouldn't be the case with this problem, you could skip the exec call and say

if (fork() == 0) {
    for (1..$time) { sleep 1; kill(0,$pid) || exit }
    kill -9, $pid;
    exit;
}

instead.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文