2

私の理解では、オブジェクトのハンドルを閉じるには、組み込みの ( ) ではなく、IO::Pipeメソッド ( ) を使用する必要があります。$fh->closeclose($fh)

先日、IO::Pipe失敗すると予想されるコマンドに対して開かれたオブジェクトに対して、習慣からビルトインを使用しました。が 0 のときに驚いた$?のですが、エラー チェックがトリガーされませんでした。

私は自分の間違いに気づきました。組み込みを使用すると、IO:Pipeを実行できず、waitpid()を設定できません$?。しかし、私が驚いたのは、perl が$?コア経由で設定せずにパイプを閉じているように見えたことです。

私が何を意味するかを示すために、小さなテスト スクリプトを作成しました。

use 5.012;
use warnings;

use IO::Pipe;

say 'init pipes:';
pipes();
my $fh = IO::Pipe->reader(q(false));
say 'post open pipes:';
pipes();

say 'return: ' . $fh->close;
#say 'return: ' . close($fh);
say 'status: ' . $?;
say q();

say 'post close pipes:';
pipes();

sub pipes
   {
   for my $fd ( glob("/proc/self/fd/*") )
      {
      say readlink($fd) if -p $fd;
      }
   say q();
   }

メソッドを使用すると、閉じた後にパイプがなくなったことを示しており、$?期待どおりに設定されています。

init pipes:

post open pipes:
pipe:[992006]

return: 1
status: 256

post close pipes:

また、ビルトインを使用すると、パイプを閉じているように見えますが、設定されていません$?:

init pipes:

post open pipes:
pipe:[952618]

return: 1
status: 0

post close pipes:

組み込みの結果がパイプの閉鎖になるのは奇妙に思えますが、設定されません$?。誰かが不一致を説明するのを助けることができますか?

ありがとう!

4

3 に答える 3

2

IO::Handle(IO::Pipe::Endサブクラスである)のコードを見ると、次のように表示されます。

sub close {
    @_ == 1 or croak 'usage: $io->close()';
    my($io) = @_;

    close($io);
}

$fh->closeを呼び出すだけのようclose $fhです。もちろん、カーテンの後ろをのぞいてはいけません。

afterIO::Pipeclose $fh(舞台裏で) 実行された後、waitpid が実行されることがわかります。

package IO::Pipe::End;

our(@ISA);

@ISA = qw(IO::Handle);

sub close {
    my $fh = shift;
    my $r = $fh->SUPER::close(@_);   # <-- This just calls a CORE::close

    waitpid(${*$fh}{'io_pipe_pid'},0)
        if(defined ${*$fh}{'io_pipe_pid'});

    $r;
}

また興味深いのは、近いPerldocからのこれです:

ファイルハンドルがパイプで開かれたものである場合、関連する他のシステムコールのいずれかが失敗した場合、またはそのプログラムがゼロ以外のステータスで終了した場合、close は false を返します。唯一の問題が、プログラムがゼロ以外で終了したことだった場合、$! 0 に設定されます。

パイプを閉じると、パイプで実行されているプロセスが終了するのも待機します-- パイプの出力を見たい場合に備えて

その後 -- そして暗黙のうちにそのコマンドの終了ステータス値を $? に入れます。および ${^CHILD_ERROR_NATIVE} 。

それはあなたの質問にすぐに答えます。

于 2013-10-29T22:20:30.870 に答える
1

But what I was surprised by was that perl seemed to still close the pipe without setting $? via the core.

Why would it? It has no way to know the process at the other end is a child, much less one for which the program should wait. Since it has no reason to call waitpid, $? isn't going to get set.

In fact, I doubt it wait for the process at the other end of the pipe even if it wanted to, because I doubt there's a way of obtaining the pid of the process at the other end of the pipe, because it's actually possible for there to be multiple processes at the other end of the pipe.

IO::Pipe::close only calls waitpid when IO::Pipe is used to "open a process".

Similarly, close only calls waitpid when open is used to "open a process".

A process "opened" using one method cannot be closed by the other.

于 2013-10-30T02:52:41.837 に答える