Perl select 返回“坏文件描述符"错误 [英] Perl select return "bad file descriptor" error

查看:89
本文介绍了Perl select 返回“坏文件描述符"错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am trying to implement inter process communication using pipes and the select command. Here is a first try:

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 的最后一条消息丢失了得到了一行:孩子 1 说:B".

The problem is that the last message from child 1 is missing Got line: "Child 1 says: B".

我运行 strace prog.pl 给出:

select(8, [3 4], NULL, NULL, NULL)      = -1 EBADF (Bad file descriptor)

在最后一个 select 调用..

on the last select call..

推荐答案

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

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

You must first remove the file descriptor from the select and then close it. Once it is closed it is no longer valid (that is fileno($fh) will return undef) and cannot be removed. And if cannot be removed select will still try to select on this (invalid) file descriptor, causing EBADF.

这篇关于Perl select 返回“坏文件描述符"错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆