2014-08-30 57 views
1

我正在嘗試使用管道和select命令來實現進程間通信。這是第一次嘗試:Perl選擇返回「壞文件描述符」錯誤

use warnings; 
use strict; 
use feature qw(say); 
use IO::Select; 
use IO::Handle; 

my @rh; 
my %childs; 
my $numChilds=2; 
$SIG{CHLD}='IGNORE'; #Reap childs automatically 

for my $i (1..$numChilds) { 
    pipe(my $pread, my $pwrite); 
    push(@rh,$pread); 
    $pwrite->autoflush(1); 
    my $child = fork(); 
    if ($child==0) { 
    runChild($i,$pwrite); 
    } 
    $childs{$pread->fileno()}={pid=>$child,id=>$i,i=>0}; 
} 

my $sel = IO::Select->new(@rh); 
while (1) { 
    say "Running select.."; 
    my @ready = $sel->can_read; 
    last if (! @ready); 
    for my $fh (@ready) { 
    say "Processing file descriptor ".($fh->fileno()); 
    chomp(my $line=<$fh>); 
    my $fd=$fh->fileno(); 
    my $child=$childs{$fd}->{id}; 
    say "Got line: \"$line\".."; 
    my $nmsg=($childs{$fd}->{i})+1; 
    if ($nmsg==2) { 
     $fh->close(); 
     $sel->remove($fh); 
     say "Select count: ".($sel->count()); 
     say "Closed fh $child.."; 
    } else { 
     $childs{$fd}->{i}=$nmsg; 
    } 
    } 
} 
say "Done."; 

sub someSeconds { return int(rand(4))+3; } 

sub runChild { 
    my ($i, $pipe)[email protected]_; 

    sleep (someSeconds()); 
    print $pipe "Child $i says: A\n"; 
    sleep (someSeconds()); 
    print $pipe "Child $i says: B\n"; 
    exit 0; 
} 

輸出是:

Running select.. 
Processing file descriptor 4 
Got line: "Child 2 says: A".. 
Running select.. 
Processing file descriptor 3 
Got line: "Child 1 says: A".. 
Running select.. 
Processing file descriptor 4 
Got line: "Child 2 says: B".. 
Select count: 1 
Closed fh 2.. 
Running select.. 
Done. 

的問題是,從孩子1的最後一條消息是缺少Got line: "Child 1 says: B"

我跑strace prog.pl這些都給:

select(8, [3 4], NULL, NULL, NULL)  = -1 EBADF (Bad file descriptor) 
上的最後一個電話 select ...

回答

2
$fh->close(); 
    $sel->remove($fh); 

,您必須首先刪除從選擇的文件描述符,然後關閉它。一旦它關閉,它不再有效(即fileno($fh)將返回undef)並且不能被刪除。如果不能刪除選擇仍然會嘗試選擇此(無效)文件描述符,從而導致EBADF。

+0

好的,但我沒有那麼做嗎? – 2014-08-30 10:48:10

+1

因爲你在做''fh-> close()'之前是'$ sel-> remove($ fh)',所以你在關閉描述符之前將它從select中移除。它一定是相反的。 – 2014-08-30 11:34:00

+1

謝謝Steffen,它現在完美的工作! – 2014-08-30 11:38:37

相關問題