加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

在什么情况下在Perl中跳过END块?

发布时间:2020-12-15 21:47:20 所属栏目:大数据 来源:网络整理
导读:我有一个长期运行的程序,它使用File :: Temp :: tempdir创建一个临时文件,有时会通过^ C中断它. 以下程序打印它创建的临时目录的名称以及其中的文件名. #!/usr/bin/env perluse strict;use warnings;use File::Temp qw[tempdir];my $dir = tempdir(CLEANUP =
我有一个长期运行的程序,它使用File :: Temp :: tempdir创建一个临时文件,有时会通过^ C中断它.

以下程序打印它创建的临时目录的名称以及其中的文件名.

#!/usr/bin/env perl
use strict;
use warnings;
use File::Temp qw[tempdir];

my $dir = tempdir(CLEANUP => 1);
print "$dirn";
print "$dir/temp.txtn";

`touch $dir/temp.txt`;
exit;

在OS X上,这将在/ var / folders中创建一个目录

如果最后一行是退出;或者死;然后文件夹将被清除,其中的临时文件将被删除.

但是,如果我们用sleep 20替换最后一行;然后通过^ C中断perl程序,临时目录仍然存在.

% perl maketemp.pl
/var/folders/dr/cg4fl5m11vg3jfxny3ldfplc0000gn/T/ycilyLSFs6
/var/folders/dr/cg4fl5m11vg3jfxny3ldfplc0000gn/T/ycilyLSFs6/temp.txt
^C
% stat /var/folders/dr/cg4fl5m11vg3jfxny3ldfplc0000gn/T/ycilyLSFs6/temp.txt
16777220 6589054 -rw-r--r-- 1 <name> staff 0 0 "Aug  1 20:46:27 2016" "Aug  1 20:46:27 2016" "Aug  1 20:46:27 2016" "Aug  1 20:46:27 2016" 4096 0 0 
/var/folders/dr/cg4fl5m11vg3jfxny3ldfplc0000gn/T/ycilyLSFs6/temp.txt
%

使用一个只调用exit的信号处理程序;确实清理目录.例如.

#!/usr/bin/env perl
use strict;
use warnings;
use File::Temp qw[tempdir];

$SIG{INT} = sub { exit; };

my $dir = tempdir(CLEANUP => 1);
print "$dirn";
print "$dir/temp.txtn";

`touch $dir/temp.txt`;
sleep 20;

正如使用“普通”信号处理程序一样

#!/usr/bin/env perl
use strict;
use warnings;
use File::Temp qw[tempdir];

$SIG{INT} = sub { };

my $dir = tempdir(CLEANUP => 1);
print "$dirn";
print "$dir/temp.txtn";

`touch $dir/temp.txt`;
sleep 20;

我尝试查看源代码(https://github.com/Perl-Toolchain-Gang/File-Temp/blob/master/lib/File/Temp.pm)以确定tempdir如何注册清理操作

这是退出处理程序安装

https://github.com/Perl-Toolchain-Gang/File-Temp/blob/master/lib/File/Temp.pm#L1716

它调用_deferred_unlink

https://github.com/Perl-Toolchain-Gang/File-Temp/blob/master/lib/File/Temp.pm#L948

修改了全局哈希值%dirs_to_unlink和%files_to_unlink,但出于某种原因使用pid $$作为键(可能是在Perl解释器分叉的情况下?不知道为什么这是必要的,因为删除目录似乎是幂等操作.)

清除文件的实际逻辑在END块中.

https://github.com/Perl-Toolchain-Gang/File-Temp/blob/master/lib/File/Temp.pm#L878

一个快速实验表明,当perl正常或异常退出时,确实会运行END块.

sleep 20;

END {
    print "5n";
}

# does not print 5 when interrupted

并在这里运行

$SIG{INT} = sub {};
sleep 20;

END {
    print "5n";
}

# does print 5 when interrupted

所以…为什么在SIGINT之后跳过END块,除非有一个信号处理程序,即使看起来它应该什么都不做?

解决方法

默认情况下,SIGINT会终止进程[1].通过kill,我的意思是该进程立即被内核终止.该过程无法执行任何清理.

通过为SIGINT设置处理程序,您可以覆盖此行为.而不是杀死进程,而是调用信号处理程序.它可能没有做任何事情,但它的存在阻止了这个过程被杀死.在这种情况下,程序不会因信号而退出,除非它选择退出(通过调用die或退出处理程序.如果确实如此,它将有机会正常清理.

请注意,如果在系统调用期间输入了定义了处理程序的信号,则系统调用将以错误EINTR退出,以允许程序安全地处理信号.这就是一旦收到SIGINT就会返回睡眠的原因.

如果您使用了$SIG {INT} =’IGNORE’;,则信号将被完全忽略.任何正在进行的系统调用都不会被中断.

>在我的系统上,man 1 kill列出了信号的默认动作.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读