Beefy Boxes and Bandwidth Generously Provided by pair Networks vroom
No such thing as a small change
 
PerlMonks  

Perl 5.8.8 threads, clean exit

by T_I (Novice)
on Feb 26, 2013 at 16:50 UTC ( #1020728=perlquestion: print w/ replies, xml ) Need Help??
T_I has asked for the wisdom of the Perl Monks concerning the following question:

Hello,

I found node 704138 with the same question for an almost similar situation, but alas, there were no usable solutions for me.

I'm working on a Perl script to shutdown AIX lpars from an AIX server (6.1) via the local HMC. As there are a lot of lpars and limited time, I've decided to use threads to split the load, with each thread a number of lpars to stop.

Now it's a big possibility that some threads will not end in time, which I want to kill after a time-out. However, the 5.8.8 version doesn't support threads->exit(). How dot I get rid of the thread?

Code snippets

use threads; our @lparList = (); my @jobs = (); my $timeOut=1; # ... fill lparList from file, 1 array element per line. # (Line can consist of 1 or more , separated lparsnames sub manageLPAR ($$) { my $action = shift; my @LPARs=split (',',$_[0]); my $die = 0; print("Thread ",threads->self->tid(), " Started.\n"); $SIG{ALRM} = sub { print("Thread ",threads->self->tid(), " got SIGALRM.\n"); $action =~ s/^S/s/; print("Timeout in $action"); if ( $action eq "stop" ) { print("p"); } print("ing @LPARs. Good bye.\n"); $die = 1; #return; threads->exit(); #die "Got SIGALRM in stopLPAR Good bye.\n"; }; ... do stuff print("Thread ",threads->self->tid(), " Finished normally.\n"); } # main foreach $lpar ( @lparList ) { push @jobs, threads->create( sub { threads->yield(); manageLPAR ($action,$lpar); }); } # Wait $timeOut seconds for thread to finish. # kill thread when time is passed. $SIG{ALRM} = sub { foreach my $job (@jobs) { if ($job->is_running) { $job->kill('ALRM'); } } }; alarm($timeOut); # Wait for all jobs to finish or timeout $_->join for @jobs; # Wait for everything to finish.

The snippet was based on another script I made for another site, with a newer Perl.

At this moment I have the 'return' option implemented with the die variable, but this doesn't work, but at least doesn't give an error. (and scares the coworkers) Whatever option I use, die, return or threads->exit(), the result is the same, no exit what so ever. (except for the error caused by threads->exit which doesn't exist)

The problem I have now is the loop which sends the ALRM signal. It just reaches 1 thread and hangs. (because it waits for the thread to exit, which it doesn't) I have to kill the thread, not knowing or even caring what it does, it just has to go.

The only solution I see at the moment is to skip threads and run external commands, wait for the timeout and kill the children. I'm stuck with this Perl version and would like to solve this in Perl, with the use of threads.

Thanks for any advice you have.

Edit: Tested with another Perl 5.8.8 version for AIX 6.1 (/opt/freeware version) and there I don't get the error, but the same result. The 'for' loop to send the signals halts after sending the signal to the first thread. I've tested with a newer perl (5.10.1) for AIX 6.1 and get the same result there. See below for output. Both threads have been configured with enough work for at least 10 seconds. (and timeout is set to 1)

Thread 1 Started. Thread 2 Started. Thread 1 got SIGALRM. Timeout in stopping <@LPARs>. Good bye. Thread 2 Finished normally.

Comment on Perl 5.8.8 threads, clean exit
Select or Download Code
Re: Perl 5.8.8 threads, clean exit
by BrowserUk (Pope) on Feb 26, 2013 at 18:55 UTC
    Thanks for any advice you have.

    Don't use signals with threads.

    Beyond that would require knowledge of how big @lparList is, and what ... do stuff is does.


    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.

      @lparList is tested with 1 and 2 elements. (elements can be 1 lpar or a , seperated list of lpars, stored in @LPARs of the thread) Both times the signal arrives, the code that has to be executed by the thread when the signal is received is executed. However, the last command (threads->exit() or the other options) are executed, but don't result in the end of the thread.

      The 'do stuff' is a large block of code used to gather all info I need to send a command via ssh (Net::OpenSSH) to a server, which then stops the machine. After the command is issued, the script checks every 30 seconds if the system is already dead. When it's dead, it continues to the next entry of @LPARs (in the test 1 thread with 1 @LPARs element, 1 thread with 2 @LPARs elements)

      The behaviour I see is that the timeout is reached, the signal ALRM is send to the 1st thread that's still running, it's acted upon (i.e. I get all expected output of the function triggered with the signal), including the call of return/die/threads->exit(), but it just simply doesn't die.

        The best suggestion I can come up with given a) your need to stay with 5.8.8; and b) the still scant information of what the threads are doing; is:

        1. discard all the signaling stuff; it isn't doing you any good anyway.
        2. detach the threads as you create them.
        3. Have your main thread sleep for the timeout period and then just fall off the end of the script.

          When the main thread ends; all the others will end also.

          foreach $lpar ( @lparList ) { threads->create( sub { threads->yield(); manageLPAR ($action,$lpar); } )->detach; } sleep $timeout; ## fall of the end of the script ## the detach threads will end when the main thread does.

          I rarely advocate abandoning threads this way; but since even if the signals 'worked', you would have no possibility for cleanup as you could never know what your code was doing when the signal to exit arrived; it makes no difference in this case.


        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.

        Another thought. You say in your OP: "the 5.8.8 version doesn't support threads->exit().". You also say you have similar code working elsewhere.

        threads is a cpan module. Why not simply upgrade to a newer version of that module that does support threads->exit?


        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.
Re: Perl 5.8.8 threads, clean exit
by Anonymous Monk on Feb 26, 2013 at 22:53 UTC
    Well, "perldoc threads" makes specific mention of signals .. much like the OP's example. Why do you say, "don't use signals in threads?"

      Because I've read more than "a mention". Specifically:

      CAVEAT: The thread signalling capability provided by this module does not actually send signals via the OS. It emulates signals at the Perl-level such that signal handlers are called in the appropriate thread. For example, sending $thr->kill('STOP') does not actually suspend a thread (or the whole process), but does cause a $SIG{'STOP'} handler to be called in that thread (as illustrated above).

      As such, signals that would normally not be appropriate to use in the kill() command (e.g., kill('KILL', $$)) are okay to use with the ->kill() method (again, as illustrated above).

      Correspondingly, sending a signal to a thread does not disrupt the operation the thread is currently working on: The signal will be acted upon after the current operation has completed. For instance, if the thread is stuck on an I/O call, sending it a signal will not cause the I/O call to be interrupted such that the signal is acted up immediately.

      The 'signals' provided by threads are little more than an inappropriately named, elaborate polling mechanism. Ill-conceived; badly implemented; mostly useless.


      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.
Re: Perl 5.8.8 threads, clean exit
by sundialsvc4 (Monsignor) on Feb 28, 2013 at 17:59 UTC

    Pardon me for resurrecting a slightly-old thread here, but I do have a question that’s just bugging me.   Even though the particular code-sample given here does not actually print a message when it sends a KILL (phony-)signal to the threads, the OP says that the signal never gets sent to the second thread.

    The example does seem to pretty closely match the one given in the PerlDoc, which at least implies that the signaling to multiple threads ought to be successful.   The example, in other words, appears to be pretty much “by the book.”

    In the “Edit,” portion, which I am just now reading, the OP says that (in another Perl version) the loop that sends the signals blocks after sending the first signal.   Is this presumably the cause of the previously described behavior, “thread #2 never gets a signal?”

    I understand that these are “not real signals,” and it’s easy enough to glom why not.   But does the implementation actually block the sender?!   Is that true of all the (all equally-phony) signal types?

    How might the OP have salvaged this situation, in your (specifically, your...) opinion?   Is there an alternate way of doing a similar thing (“interrupting a child thread, more or less”) that would have been successful and reliable across versions?   Or is it simply, “irreconcilably broken?”

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1020728]
Approved by marto
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others exploiting the Monastery: (12)
As of 2014-04-21 13:08 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    April first is:







    Results (495 votes), past polls