http://www.perlmonks.org?node_id=997231


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

Signals are, at best, on platforms that support them natively, a very crude form of IPC.

Yes, everyone is quick to suggest that, and yet not offer any working alternatives. Shared memory is not always an option. Port and pipe communication is excessive.

If my entire process is being terminated from the keyboard, by a scheduler, or the O/S, a signal is exactly what I'm going to get, and I want to cleanup properly which it does. I was just trying to use the same logic internally to force the cleanup based on a timer.

Sending every known signal: Utter desperation. :)

Sending no, capturing yes. I wasn't sending every signal but one, maybe two. Understanding how the app responds to many different situations is just good testing.

For a solution to your problem that works, see Re^3: trying to get timeout to work (easier with threads).

Note that your example still uses the devilish signal. But yes, this seems to be the most promising suggestion yet. Resolves the blocking I/O by pushing it another thread deeper. Thank you.

Replies are listed 'Best First'.
Re^3: Signals vs. Windows
by BrowserUk (Patriarch) on Oct 04, 2012 at 14:34 UTC
    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

      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