http://qs321.pair.com?node_id=997242


in reply to Re^2: Signals vs. Windows
in thread Signals vs. Windows

Note that your example still uses the devilish signal.

Yes, but in the way it was intended -- as an IPC mechanism, not ITC.

Resolves the blocking I/O by pushing it another thread deeper. Thank you.

Indeed. (Be sure to look at the stack_size parameter to threads.)

But, it isn't actually necessary to go one thread deeper. If your current main/parent thread can attempt to send a signal to its child threads to terminate them, it could also send that signal directly to the processes those child threads are waiting on, thus cutting out the middle man and the need for an extra thread.

All that would be required is to shared the pids of those processes with the parent thread so that it knows where to send the signal when the time is right.

The following script starts 5 asynchronous, piped subprocesses in threads that will each run for 5 seconds producing one 'line' of output per second. The threads share the pids of those processes with the main thread via a shared array indexed by their thread ids.

The main thread then applies timeouts to those processes ranging from 3 to 7 seconds, killing them after the appropriate delay. It then gathers whatever output they had produced before the timeout from the threads by joining them.

You can see -- in the console output after the __END__ -- that the first two processes were terminated (SIGINT) after 3 and 4 seconds respectively and their output was truncated. The other 3 complete their output and terminate normally.

#! perl -slw use strict; use Time::HiRes qw[ sleep time ]; use threads; use threads::shared; my @pids :shared; sub asyncPipedProc { my $tid = threads->tid; my $cmd = shift; $pids[ $tid ] = open my $pipe, '-|', $cmd or die $!; my @input; push @input, $_ while <$pipe>; return @input; } my $cmd = q[ perl -E"$|++; sleep(1), say for 1 .. 5" ]; my @running; for my $timeout ( 3 .. 7 ) { push @running, [ threads->new( \&asyncPipedProc, $cmd, $_ ), time() + $timeout ]; } while( @running and sleep 0.1 ) { for my $i ( reverse 0 .. $#running ) { if( $running[ $i ][ 1 ] < time() ) { kill 2, $pids[ $running[ $i ][ 0 ]->tid ]; printf "From thread %d got:\n%s", $running[ $i ][ 0 ]->tid, join'', $running[ $i ][ 0 ]->join; splice @running, $i, 1; } } } __END__ C:\test>multi-timeout.pl Terminating on signal SIGINT(2) From thread 1 got: 1 2 3 Terminating on signal SIGINT(2) From thread 2 got: 1 2 3 4 From thread 3 got: 1 2 3 4 5 From thread 4 got: 1 2 3 4 5 From thread 5 got: 1 2 3 4 5

With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.

RIP Neil Armstrong

Replies are listed 'Best First'.
Re^4: Signals vs. Windows
by DanEllison (Scribe) on Oct 04, 2012 at 15:06 UTC

    Yes, I thought about that. But the child thread is doing more than just executing the command. It is also logging the output, start, stop, status.... I'd like the child thread to ultimately send the signal to external program so that it can also record the fact in my log.

    But that's all okay because now the child thread is running asychonously and I can move the timer from the parent down to the child. So in essence, the parent no longer needs to signal the child, and logically you are right that we don't need to be another level deep, but that I am really moving down a level in my hierarchy of threads.

      But the child thread is doing more than just executing the command. It is also logging the output, start, stop, status....

      I see no conflict with that and what I posted accept that instead of the parent setting the end time when it starts the thread, you have the kids set the end time -- in a shared data structure -- when it starts the process.

      Either way works, but if all your main thread is going to do while the kids are doing their thing is wait for them, I see no reason not to have it make itself useful and fulfill the timeout roll. Saving a second layer of threads is just a bonus.

      But whichever works for you ...


      With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.

      RIP Neil Armstrong