【问题标题】:Perl select return "bad file descriptor" errorPerl 选择返回“错误的文件描述符”错误
【发布时间】:2014-08-30 10:32:22
【问题描述】:

我正在尝试使用管道和select 命令实现进程间通信。这是第一次尝试:

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)=@_;

  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 通话中..

【问题讨论】:

    标签: perl


    【解决方案1】:
      $fh->close();
      $sel->remove($fh);
    

    您必须首先从选择中删除文件描述符,然后将其关闭。一旦关闭它就不再有效(即fileno($fh) 将返回 undef)并且不能被删除。如果不能被删除,select 仍然会尝试在这个(无效的)文件描述符上进行选择,从而导致 EBADF。

    【讨论】:

    • 好的,但我不就是这么做的吗?
    • 由于您在执行之前执行$fh-&gt;close()$sel-&gt;remove($fh),因此您在将描述符从选择中删除之前将其关闭。肯定是反过来的。
    猜你喜欢
    • 2015-09-25
    • 1970-01-01
    • 1970-01-01
    • 2014-03-14
    • 2019-06-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-08
    相关资源
    最近更新 更多