views:

306

answers:

3

Is there any POSIX signals that I could utilize in my Perl program to create event-driven programming? Currently, I have multi-process program that is able to cross communicate but my parent thread is only able to listen to listen at one child at a time.

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

The problem is that the parent sits in a continual wait state until it receives it a signal from the first child before it can continue on. I am relying on 'pipe' for my intercommunication.

My current solution is very similar to: http://stackoverflow.com/questions/2558098/how-can-i-use-pipe-to-facilitate-interprocess-communication-in-perl

If possible I would like to rely on a $SIG{...} event or any non-CPAN solution.

Update:

As Jonathan Leffler mentioned, kill can be used to send a signal:

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

My solution will be to send a USR1 signal to my child process. This event tells the parent to listen to the particular child.

child:

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

parent:

$SIG{USR1} = {
   #get child pid?
   sysread($array[$pid]{'childPipe'}, $msg, $buffer);   
};
  1. But how do I get my the source/child pid that signaled the parent? Have the child Identify itself in its message.
  2. What happens if two children signal USR1 at the same time?

Update 2: Solution

I went with a select that utilized a vector approach for non-blocking IO. For those that come across this thread check out: http://docstore.mik.ua/orelly/perl/cookbook/ch07_14.htm as it covers both the vector way and the IO::Select module. I understand the IO::Select module would have been more elegant, but I was more interested in learning new mechanics of Perl. Thank you everyone for your help.

Exert:

$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
  }
}
+10  A: 

If you want to do event-driven programming, take a look at one of the CPAN event modules, such as POE, Coro, or AnyEvent before you invent your own thing.

brian d foy
+3  A: 

To answer the direct question, SIGUSR1 and SIGUSR2 are intended for 'user-defined' purposes - so you could use them.

You might be better off looking at a pre-existing system, though.

Jonathan Leffler
+5  A: 

You can use select to monitor communications channels (note: if you are on Win32 select can only be used on a socket).

So you can use code like this:

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

Take a look at the UDP example in perlipc. It uses the select built-in. I prefer the core IO::Select module to the select built-in, it's much easier to read.

Update: You really should consider using an event framework like POE, Event or Coro. There's a pretty good list of options in this perlmonks thread. Don't fear CPAN.

daotoad
I will take a look. I would definitely consider a CPAN packaged solution professionally. I am new to Perl and Unix Signals so I am trying to wrap my head around the inner workings.
Shiftbit
ok, but signals have nothing to do with this problem. pipes already have a mechanism for signaling that they are readable. it's called select. (or epoll, or kqueue, or ...)
jrockway
@Shiftbit, signals are totally unnecessary. `select` will allow you to monitor multiple handles for available data. The blocking issues you have are related to `<>` looking for a line of test, and not having your handles in non-blocking mode. My example shows how to use `read` and make your handles non-blocking.
daotoad