在Windows上捕获SIGINT(和其他信号)

4

为什么需要这个简单的脚本:

#! perl -w

use strict;
use warnings;
$| = 1;

my $LOCKFILE = "$0.lock";

sub mklock {
    open my $lf, ">", $LOCKFILE;
    print $lf $$;
    close $lf;
}

sub rmlock { unlink $LOCKFILE; }

sub clean_exit { rmlock;  exit 0; }

sub work {
    print "working...";
    sleep 10;
    # although `sleep 1 foreach (1..10);`
    # *does* interrupt---between `sleep`s--see my answer
    print "done.\n"
}

$SIG{INT} = "clean_exit";

mklock;
work;
rmlock;

在Debian上工作但在Windows上不行?

  • 在Windows上,当此脚本正在运行时,Ctrl+C会被忽略
  • 在Debian上,干净的退出按预期执行
  • 使用$SIG{INT} = \&clean_exit;,行为似乎相同
  • (如果我对SIGHUP做同样的事情 ($SIG{HUP} = "clean_exit";),窗口将关闭,但无论如何都不会执行干净的退出)

(好吧,我承认这是Strawberry perl 5, version 14, subversion 2 (v5.14.2) built for MSWin32-x86-multi-thread在Windows 7 amd64上 -vs- perl, v5.10.1 (*) built for x86_64-linux-gnu-thread-multi在Debian 6.0.4箱子上,但我怀疑对于这种基本的东西来说并不重要。 编辑:我刚刚在安装了ActiveState perl 5.12的类似机器上检查了它,结果是一样的,所以显然问题并不仅限于Strawberry。)

我知道perlport已经说得很清楚了,

不要指望信号或 %SIG 能做任何事情。

但肯定有办法... (而且,我想理解。)

那么应该怎样做才能有所不同呢?


非常奇怪 - 在我的cygwin终端和标准cmd窗口中,Ctrl-C都可以正常工作(perl的两个实例都是cygwin)。 - Anya Shenanigans
@Petesh 在我的电脑上,Cygwin可以正常工作。(不幸的是,Cygwin对于我的“实际”问题无法解决,因为我需要在一些毫无防备的Windows机器上部署我的脚本。然后进行很多非常Windows风格的操作 :)) - Alois Mahdal
请看我的回答 - Strawberry 遵循 Windows 约定,这意味着 Alt+Break 可以工作,但 Ctrl+C 不行。 - Anya Shenanigans
3个回答

4

你可以使用sigtrap模块:

use sigtrap 'handler', \&cleanup, 'normal-signals';

当捕获到信号并将信号标识作为参数传递时,这将调用方法cleanup


那行代码原样(将“cleanup”替换为“clean_exit”)会导致脚本在草莓Perl下终止。 - Anya Shenanigans
@Petesh:无法使用strawberry进行测试,但在ActiveState上运行良好。cleanup函数也会在脚本正常终止时被调用... - eckes
这很棒,因为它增加了更多的调试潜力。(您可以记录发生了什么...)然而,在Win上,当我关闭cmd.exe窗口时,它无法使用HUP :/ - Alois Mahdal

1

在添加了一些更多的打印后,我发现实际上这段代码是可以工作的,只是在sleep期间没有中断。

所以,将sleep 60更改为更“现实”的sleep 1 foreach (1..10);会带来更可接受的行为。

当然,在Windows和*nix上它们的工作方式仍然不同。


1

在 DOS 应用程序中遵守 Unix 行纪律是一种奢侈而不是权利。

它确实遵守 Ctrl+Break,这是 Windows 中 Ctrl+C 的等效方式。

编辑 改为 Ctrl+Break - 这就是我使用 Mac 键盘的后果。

为了测试中断处理,您应该在您的工作子程序中使用以下循环,否则它会等待整个 sleep 完成后才触发处理程序:

sub work {
    print "working...";
    my $i = 0;
    while ($i < 10) {
       sleep(1);
       $i--;
    }
    say "done."
}

这样可以更容易地检测按键 - 在睡眠期间不会检测到中断处理。

让我感到困惑的是 - INT处理程序现在正在工作!

编辑 Perl的原始源代码声称它应该支持HUP作为关闭窗口事件,但当我单击CMD窗口的关闭时,该事件似乎没有被传递。


谢谢,我不知道那个。然而,如果你 触碰 %SIG,在按下 Ctrl+C 时会得到 working...Terminating on signal SIGINT(2) 的完美混淆。(但话说回来,DOS 上还有什么不混淆的呢……?) - Alois Mahdal
实际上,Ctrl-C和Ctrl-Break一直是DOS概念“永远”。 - ikegami

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接