【问题标题】:Can I use POSIX signals in my Perl program to create event-driven programming?我可以在我的 Perl 程序中使用 POSIX 信号来创建事件驱动编程吗?
【发布时间】:2011-02-03 22:18:25
【问题描述】:

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

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

问题是父母处于持续等待状态,直到它收到第一个孩子的信号才能继续。我依靠“管道”进行交互。

我目前的解决方案非常类似于:How can I use `pipe` to facilitate interprocess communication in Perl?

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

更新:

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

kill USR1 => $$; # send myself a SIGUSR1

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

孩子:

kill USR1 => $parentPID if($customEvent);
syswrite($parentPipe, $msg, $buffer);
#select $parentPipe; print $parentPipe $msg;

父母:

$SIG{USR1} = {
   #get child pid?
   sysread($array[$pid]{'childPipe'}, $msg, $buffer);   
};
  1. 但是我如何获得向父级发出信号的源/子 pid? 让孩子在其信息中表明自己的身份。
  2. 如果两个孩子同时发出 USR1 信号会怎样?

更新 2:解决方案

我选择了一个使用矢量方法进行非阻塞 IO 的选择。 对于遇到此线程的人,请查看:Perl Cookbook: 7.22. Reading from Many Filehandles Without Blocking,因为它涵盖了向量方式和 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
  }
}

【问题讨论】:

  • 你知道,你可以把这些东西写到管道里……不需要为这些东西发送信号。在父级中,在读取前使用“选择”。
  • 您的意思是process 还是thread?差别很大。
  • 我在使用“select”和 运算符时遇到的问题是它等待当前选定的子进程响应并忽略所有其他子进程,直到它得到响应。
  • 好吧,不要使用 。使用带有非阻塞标志的 sysread。或者不要这样做,并使用适当的框架。
  • @Shiftbit 不是那个选择,另一个选择。

标签: perl ipc posix signals unix


【解决方案1】:

如果您想进行事件驱动编程,请先查看 CPAN 事件模块之一,例如 POECoroAnyEvent,然后再发明自己的东西。

2020 年更新

我正在使用 Mojo::EventEmitter 执行此操作,我在我的书 Mojo Web Clients 中对此进行了简要介绍。

【讨论】:

    【解决方案2】:

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

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

    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;
    }
    

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

    更新:你真的应该考虑使用像 POE、Event 或 Coro 这样的事件框架。 this perlmonks thread 中有一个很好的选项列表。不要害怕 CPAN。

    【讨论】:

    • 我去看看。我肯定会专业地考虑使用 CPAN 打包解决方案。我是 Perl 和 Unix Signals 的新手,所以我想了解一下内部工作原理。
    • 好的,但是信号与这个问题无关。管道已经有一种机制来表明它们是可读的。它被称为选择。 (或 epoll,或 kqueue,或 ...)
    • @Shiftbit,信号完全没有必要。 select 将允许您监视多个句柄以获取可用数据。您遇到的阻塞问题与 <> 寻找测试线有关,并且您的句柄没有处于非阻塞模式。我的示例展示了如何使用 read 并使您的句柄非阻塞。
    【解决方案3】:

    为了回答直接问题,SIGUSR1 和 SIGUSR2 旨在用于“用户定义”目的 - 因此您可以使用它们。

    不过,您最好查看一个预先存在的系统。

    【讨论】:

      猜你喜欢
      • 2014-03-10
      • 2020-08-30
      • 2011-01-16
      • 1970-01-01
      • 2010-09-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-30
      相关资源
      最近更新 更多