我可以在Perl程序中使用POSIX信号来创建事件驱动编程吗?

5 unix perl posix signals ipc

是否有任何POSIX信号可以在我的Perl程序中用于创建事件驱动编程?目前,我有多进程程序,能够交叉通信,但我的父线程只能听一次听一个孩子.

foreach (@proc) {
  sysread(${$_}{'read'}, my $line, 100); #problem here
  chomp($line);
  print "Parent hears: $line\n";
}
Run Code Online (Sandbox Code Playgroud)

问题是父母处于持续等待状态,直到它从第一个孩子收到信号才能继续.我依靠'管道'来进行相互沟通.

我目前的解决方案非常类似于:如何使用`pipe`来促进Perl中的进程间通信?

如果可能的话,我想依靠$ SIG {...}事件或任何非CPAN解决方案.

更新:

正如Jonathan Leffler所说,kill可用于发送信号:

杀USR1 => $$; #给自己发一个SIGUSR1

我的解决方案是向我的子进程发送USR1信号.此事件告诉父母听取特定的孩子.

儿童:

kill USR1 => $parentPID if($customEvent);
syswrite($parentPipe, $msg, $buffer);
#select $parentPipe; print $parentPipe $msg;
Run Code Online (Sandbox Code Playgroud)

父:

$SIG{USR1} = {
   #get child pid?
   sysread($array[$pid]{'childPipe'}, $msg, $buffer);   
};
Run Code Online (Sandbox Code Playgroud)
  1. 但是,如何获得发信号通知父母的源/子pid? 让孩子在其信息中识别自己.
  2. 如果两个孩子同时发出USR1信号会怎样?

更新2:解决方案

我选择了一个使用矢量方法进行非阻塞IO的选择.对于遇到此线程的人,请查看:http://docstore.mik.ua/orelly/perl/cookbook/ch07_14.htm,因为它涵盖了向量方式和IO :: Select模块.我理解IO :: Select模块会更优雅,但我更感兴趣的是学习Perl的新机制.感谢大家的帮助.

发挥:

$rin = '';
# repeat next line for all filehandles to poll
vec($rin, fileno(FH1), 1) = 1;
vec($rin, fileno(FH2), 1) = 1;
vec($rin, fileno(FH3), 1) = 1;

$nfound = select($rout=$rin, undef, undef, 0);
if ($nfound) {
  # input waiting on one or more of those 3 filehandles
  if (vec($rout,fileno(FH1),1)) { 
      # do something with FH1
  }
  if (vec($rout,fileno(FH2),1)) {
      # do something with FH2
  }
  if (vec($rout,fileno(FH3),1)) {
      # do something with FH3
  }
}
Run Code Online (Sandbox Code Playgroud)

bri*_*foy 9

如果您想进行事件驱动编程,请在创建自己的事物之前先查看一个CPAN事件模块,例如 POE,CoroAnyEvent.


dao*_*oad 4

您可以使用select来监视通信通道(注意:如果您在 Win32 上,select 只能在套接字上使用)。

所以你可以使用这样的代码:

use IO::Select;
use IO::Handle;

...

$_->blocking(0) for @handles;

while( 1 ) {
    my $s = IO::Select->new( @handles );

    for my $h ( $s->can_read( 1 ) ) {

        my $data = read_handle($h);
        process_handle_data( $data );
    }

}

sub read_handle {
    my $h = shift;

    my $got = '';

    1 while read( $h, $got, 1024, length $got );

    return $got;
}
Run Code Online (Sandbox Code Playgroud)

看一下 perlipc 中的 UDP 示例。它使用内置的 select。IO::Select与内置模块相比,我更喜欢核心模块select,它更容易阅读。

更新:您确实应该考虑使用 POE、Event 或 Coro 等事件框架。这个 perlmonks 线程中有一个非常好的选项列表。不要害怕 CPAN。

  • 好的,但是信号与这个问题无关。管道已经有一种机制来表明它们是可读的。这就是所谓的选择。(或者 epoll,或者 kqueue,或者...) (2认同)