Gary Yang has asked for the wisdom of the Perl Monks concerning the following question:

Hi,
I use threads to speed up my program. Sometimes one of the threads dead or extremely slow. I would like to kill that thread, disregard result of that thread if it runs more than 30 seconds. Is there a way to set timeout for a thread? Please help.

Thank you

Replies are listed 'Best First'.
Re: Threads Timeout
by BrowserUk (Patriarch) on Jan 20, 2012 at 23:10 UTC

    You could try this:

    #! perl -slw use strict; use threads; my @t = map async( sub { my $tid = threads->tid; my $worktime = shift; print "Thread $tid started with a worktime of $worktime"; eval { local $SIG{ ALRM } = sub { die 'times up' }; alarm 10; ## simulate doing work here sleep $worktime; print "Thread $tid: all done"; }; print "Thread $tid ended ", $@ ? " with error: $@" : 'normally'; }, 2*$_ + $ARGV[ 0 ] ), 1 .. 4; $_->join for @t; __END__ C:\test>junk78 5 Thread 1 started with a worktime of 7 Thread 2 started with a worktime of 9 Thread 3 started with a worktime of 11 Thread 4 started with a worktime of 13 Thread 1: all done Thread 1 ended normally Thread 2: all done Thread 2 ended normally Thread 4 ended with error: times up at C:\test\junk78.pl line 10. Thread 3 ended with error: times up at C:\test\junk78.pl line 10.

    Whether this works -- ie. will interrupt what you are doing when the alarm goes off is subject to the same limitations as with normal perl.

    Due to Deferred (safe) signals introduced in 5.7.x, there are some things it won't interrupt until the opcode completes or times out. But that's a 'Perl-thing' rather than a 'threads-thing'.


    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.

    The start of some sanity?

Re: Threads Timeout
by zentara (Cardinal) on Jan 21, 2012 at 11:32 UTC
Re: Threads Timeout
by Khen1950fx (Canon) on Jan 21, 2012 at 21:34 UTC
    I took BrowserUk's example and added Time::Out. It returns a slightly different result.
    #!/usr/bin/perl -l use strict; use warnings; no warnings 'uninitialized'; use threads; use Time::Out qw(timeout); my (@t) = map( async( sub { my $tid = 'threads'->tid; my $worktime = shift @_; print "Thread $tid started with a worktime of $worktime"; eval { sub test { timeout 10, @_ => sub { print "$_[0]"; }; } }; print "Thread $tid ended ", $@ ? " with error: $@" : "norm +ally"; }, 2 * $_ + $ARGV[0]), 1..4); $_->join foreach (@t);
      I took BrowserUk's example and added Time::Out. It returns a slightly different result.

      Not slightly different. Completely different. And wrong.

      Your code isn't doing anything like what you think it is doing. Actually, it isn't doing anything at all.

      This:

      eval { sub test { timeout 10, @_ => sub { print "$_[0]"; }; } };

      evals the sub test into existence, but then it never actually calls that sub.

      • The eval is pointless, because the code inside it can never fail.
      • The code inside the sub is useless, because it is never called.
      • You render the parameter passed to the thread useless, by never using it.

        Which in turn renders the purpose of the demonstration -- showing that the timeout is effective -- useless.

      • You've used a module which itself is useless, because it uses almost 100 lines of code to do what you can standard Perl in 2 lines.

        And with no value add.

      • And you compounded that by using it incorrectly, rendering it even less useful.
      • Your code ends up being the exact equivalent of:
        #! perl -slw use strict do { my $tid = int( rand ); #'threads'->tid; my $worktime = shift @_; print "Thread $tid started with a worktime of $worktime"; print "Thread $tid ended ", $@ ? " with error: $@" : "normally"; } for 1 .. 4;

      In other words, your post is ... I'll let you guess the word I'm thinking of here. (Sorry, but it's true!)

      FWIW: I applaud you for having a go :)


      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.

      The start of some sanity?

Re: Threads Timeout
by locked_user sundialsvc4 (Abbot) on Jan 23, 2012 at 13:45 UTC

    The basic idea here is definitely the right approach:   let the thread set a timeout upon itself, so that when 31 seconds arrive ... the thread does not keep going, wasting CPU time to produce a result that will never be interesting.   Instead, it dies.   This is much more reliable in-practice than having a separate process out there with a stopwatch in its hands, which is quite vulnerable to edge-case race conditions.   Let each thread be fully responsible for its own outcome, whatever that may be, and for dealing with it and for reporting it.

    The only thing that I do not see here (having only glanced at the responses most casually and briefly, is that usually the thread, before dying, needs to in some way signal a waiting parent that it has failed.   Perhaps the final-status of the thread is enough to do that, or you might need to add code to send some kind of a message to someone (perhaps, to a process that isn’t the parent) to the effect that such-and-such a unit of work could not be completed timely.   Several ways to tackle that, of course ... maybe the parent does it, and maybe not ... and mind you, I’m not suggesting that the solutions offered here so-far do not work because they most clearly do.

      The only thing that I do not see here ... is that usually the thread, before dying, needs to in some way signal a waiting parent that it has failed.

      You are suggesting that the children signal their parent. Inter-thread communication with a bandwidth of a whole 1-bit.

      What would the parent do with the knowledge that 'one of its kids has died'? With that 1 bit bandwidth you cannot even communicate which child has died.

      A bit like a station announcer telling you: "a train arrived or departed".

      And that is ignoring the fact that inter-thread signalling doesn't work as there is no way to distinguish the source of the signal -- inter-thread or inter-process -- never mind which thread. In addition, every thread within the process that has a signal handler defined, will receive every signal regardless of where it originated from.

      All a little pointless when you have the unlimited bandwidth of the return from the join.

      I just wonder why you felt the need to suggest this when you've obviously not even attempted to think through the implications, much less actually tried it.


      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.

      The start of some sanity?

        I certainly did not mean “signal” in a purely binary way.   Nor, so specific.   Rather, a better word might simply be, “inform” or “notify.”

        The thread, presumably, is doing something; it is working on some particular request or unit of work, presumably in teamwork with some other thread(s).   So, if this thread has timed-out, in the grand scheme of things it probably needs to inform someone (maybe not the parent) about something related to that unit-of-work’s new status.   It is just a worker bee, not the workflow manager.

        “Putting a bomb in your own backpack” is the best way of handling timeouts vs. having some executioner-process out there with a loaded gun, and as far as I know that’s how every workflow management package does it.   The worker sets the timer, does the work, and, 99.9% of the time, clears the timer, sends a success-notification to whomever needs to receive it, and all is well.   Maybe it terminates, or maybe it simply starts afresh on a new unit of work.   Timeout throws it into an exception-handler ... the thread is still alive but now it’s in that handler ... and it sends a failure message to the appropriate parties before (perhaps...) cordially terminating itself.   Whether it succeeds or it fails, with one unit of work or with many, it always exits the stage graciously, never having been murdered by anyone.