Perl:从后台线程关闭open2句柄

时间:2019-01-02 20:49:49

标签: multithreading perl handle

我只是在尝试找出如何正确使用open2函数。

请参阅下面的示例。它适用于较小的$max,但是很自然,如果我向$hIn写足够长的时间,那么最终它将被阻塞,因为没有东西连续读取输出上的数据。

use 5.26.0;
use IPC::Open2;
my $max = 100000;
my $pid = open2(my $hOut, my $hIn, "cat") || die "failed 'cat': $!";
{
    my $cnt = 0;
    #When $max is big (e.g. 100000) so the code below will get blocked
    #when writing to $hIn
    while ($cnt<$max) {say $hIn $cnt++;}
    close($hIn) || say "can't close hIn";
}
while(<$hOut>) { print; }
close($hOut) || say "can't close hOut";
waitpid( $pid, 0 );

我能想到的唯一解决方案是启动另一个线程,该线程将在后台进行编写。

使用下面的代码,我可以根据需要向$hIn中写入尽可能多的数据,并在主线程中读取它们,但是$hIn似乎并没有关闭。因此,while(<$hOut>)在等待更多输出时将永远不会结束。

use 5.26.0;
use threads;
use IPC::Open2;
my $max = 100000;
my $pid = open2(my $hOut, my $hIn, "cat") || die "failed 'cat': $!";
my $thr = threads->create(sub {
    my $cnt = 0;
    while ($cnt<$max) {say $hIn $cnt++;}
    #The close does not have any effect here (although no error is produced)
    close($hIn) || say "can't close hIn";
});
#This outputs all the data written to $hIn but never leaves the loop...
while(<$hOut> ) { print; }
close($hOut) || say "can't close hOut";
$thr->join;
waitpid( $pid, 0 );

我的问题是:

  • 提供了使用线程的方法,可以如何从后台线程关闭文件句柄?
  • 如果还不行(实际上在Perl中不建议使用use threads),那么有人可以提供open2的工作示例,该示例可以写入和读取大量数据,而不会有阻塞等待读者或阅读器的风险。作家?

编辑:按照您的建议,这里是使用IPC :: Run的上述代码的实现:

use 5.26.0;
use IPC::Run qw/ run /;
my $max = 1000000;
run sub {
        my $cnt = 0;
        while ($cnt<$max) {say $cnt++;}
    },
    "|", "cat",
    "|", sub {
        while(<> ) {
            print;
        }
    }
    or die "run sub | cat | sub failed: $?";

它运行无缺陷,代码可读性强……我很高兴了解此模块。谢谢大家!

但是,我认为这个问题尚未得到解答。如果无法直接使用open2编写此功能,那为什么还会存在并使人们感到困惑呢?同样,无法从其他线程关闭文件句柄在我看来也像是个错误(肯定是-关闭应该至少报告一个错误)。

1 个答案:

答案 0 :(得分:4)

  1. 您的程序停止,因为它正在写入的管道已满。
  2. "firstClass secondClass active"的管道已满,因为cat停止从其中读取数据。
  3. cat之所以停止,是因为它写入的管道已满。
  4. cat中的管道已满,因为您的程序未从其中读取数据。

因此,您有两个程序互相等待以执行某项操作。这是一个僵局。

低级解决方案是使用cat来监视管道的两端。

高级解决方案是让IPC::RunIPC::Run3为您完成这项艰苦的工作。

select