如何在 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 发布,一个错误在全局销毁期间跳过了文件句柄的关闭。
据我所知,在 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 发布,一个错误在全局销毁期间跳过了文件句柄的关闭。