2

假设我有一个打开的文件句柄,或者在退出脚本之前我必须修复的任何东西。我也有一个很长的循环,如果进程收到一个信号,我想打破循环。最干净的方法是什么?

这是问题的说明;

use sigtrap 'handler' => \&sigint_handler, 'INT';

sub sigint_handler {
  print("\nI see you are trying to escape this evil infinite loop,
but there is nothing that I can do to help you :(\n");
}

my $the_developper_is_unable_to_end_this_mess = 1;

open(my $handle, "< some.important.file");

while($the_developper_is_unable_to_end_this_mess) {
  print("And the evil loop rolls again and again...\n");
  sleep(3);
}

close($handle);

print("everything went better than expected\n")
4

1 回答 1

4

绝对应该运行的清理代码可以放入一个END块中:

END {
  print "This is run before the program exits\n";
}
print "This is some normal code\n";

输出:

This is some normal code
This is run before the program exits

但是,END当进程从信号终止时,块不会运行,除非您实现自己的信号处理程序——并且如果它所做的只是调用exit.

END因此,当您使用 SIGINT 终止此代码时,将不会打印此代码:

END { print "END\n" }
sleep 4;

但是这个会:

END { print "END\n" }
local $SIG{INT} = sub { exit 1 };
sleep 4;

这些处理程序是动态作用域的,因此您可以将一个在外部无效的循环中放入:

 my $run = 1;
 while ($run) {
   local $SIG{INT} = sub { $run = 0 };
   print "zzz\n";
   sleep 3;
 }
 print "done!\n";

当然你也可以使用sigtrap

 my $run = 1;
 while ($run) {
   use sigtrap handler => sub { $run = 0 }, 'INT';
   print "zzz\n";
   sleep 3;
 }
 print "done!\n";

PS:文件句柄在超出范围/进程退出时会自动关闭。如果句柄只是从文件中读取,则不会有任何缓冲问题或取决于句柄的其他进程,因此close $fh在这种情况下您可以放心地忘记。

于 2013-08-28T17:48:13.410 回答