如何在 Perl 中中断对词法文件句柄的读取?

How to interrupt a read of a lexical filehandle in Perl?

据我所知,在 Perl 中一段时间​​后中断某事的模式如下:

#!/usr/bin/perl
local $SIG{ALRM} = sub { die "timed out\n"; };
my $pid;
eval {
    alarm 10;
    # do stuff
    alarm 0;
};
print "done\n";
kill(9, $pid) if $pid;

所以“某事”的一个例子是打开一个可能随机挂起的子进程进行读取。出于测试目的对其进行模拟按预期工作:

# replace "# do stuff" with:
    $pid = open FH, "sleep 120|";
    my $line = <FH>;
    close FH;

但是,这些全局命名的东西是不能传递给其他子程序的,所以我很想用下面的实现:

# replace "# do stuff" with:
    $pid = open my $fh, "sleep 120|";
    my $line = <$fh>;
    close $fh;

...但是当我 运行 这个时,Perl 脚本无限期挂起!为什么?

当没有剩余对变量的引用时(可能是它超出范围的结果),Perl 会清理与该变量关联的资源。析构函数被调用,内存被释放,文件句柄被关闭等等,即使变量因为异常而不再被引用也是如此。

当使用open -|open |- 创建的文件句柄关闭时,Perl 等待子进程结束。这种情况不仅发生在对 close 的显式调用中,还发生在由于破坏打开的文件句柄而发生的隐式关闭中。

在您的场景中,由于文件句柄的隐式关闭,Perl 正在等待子进程完成。它不会无限期地挂起,但在 120 秒的剩余时间里,子进程会结束。这是应该对程序的两个版本观察到的行为,也是对两个版本都观察到的行为,除非使用的是旧版本的 Perl。直到 9 年前的 5.18 发布,一个错误在全局销毁期间跳过了文件句柄的关闭。