2013-10-29 49 views
2

我的理解是,關閉IO::Pipe對象的句柄應該使用方法($fh->close)而不是內置(close($fh))來完成。

有一天,我瘋狂地在IO::Pipe對象中使用內置的習慣,這個對象打開了一個我預計會失敗的命令。當$?爲零時,我感到很驚訝,並且我的錯誤檢查沒有被觸發。

我意識到自己的錯誤。如果我使用內置的,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: 

對於我來說,在管道關閉中的內置結果似乎很奇怪,但沒有設置$?。任何人都可以解釋這種差異嗎?

謝謝!

回答

2

如果你看一下代碼IO::Handle(其中IO::Pipe::End是一個子類),你會看到以下內容:

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

    close($io); 
} 

它看起來像$fh->close只是調用close $fh。當然,我們不應該在幕後偷看。

我們可以看到IO::Pipe做了close $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。

關閉的管道也等待在管道上執行的進程退出 --in情況下,你希望在管道的輸出看

之後 - 和含蓄提出的退出狀態值那命令 變成$?和$ {^ CHILD_ERROR_NATIVE}。

即時回答您的問題。

1

但是我驚訝的是,perl似乎還沒有設置$關閉管道?通過核心。

爲什麼會這樣?它無法知道另一端是一個孩子的過程,更不用說該程序應該等待的過程。由於它沒有理由撥打waitpid,因此$?不會被設置。

事實上,我懷疑它等待管道另一端的進程,即使它想要,因爲我懷疑有一種方法可以獲得管道另一端的進程的PID,因爲它是實際上可能在管道的另一端有多個進程。

IO::Pipe::close當IO :: Pipe用於「打開進程」時,僅調用waitpid

同樣,close只有調用waitpidopen用於「打開進程」。

使用一種方法「打開」的過程不能由另一方關閉。

0

事實證明,我的困惑源於一個有缺陷的假設,即消失的管道與完整的過程終止相吻合。這似乎並非如此,因爲該流程仍可用於wait()

> perl -MIO::Pipe -le 'my $io = IO::Pipe->reader(q(false)); close($io); print $?; print wait(); print $?' 
0 
8857 
256