in reply to Threads question

Unfortunately, perlthrtut is probably the single worst piece of documentation in the entire perl docset. And the second worst advert for Perl + threads.

The warning you are getting is indicating that the first thread started in your program--that is, the thread started when the program is run; the thread from which you create your other 3 threads; sometimes referred to as the main thread--ended, because it 'ran off the end of the script', before the other 3 threads had ended.

And, because the main thread, in a threaded program, is also the process, when the main thread dies, all other threads die also.

The reason the some or all of the other 3 threads hadn't died or 'gone away' earlier, despite that at least one or two of them had finished doing whatever they were doing, is because threads can return values, just like processes can. And just as with fork, they don't die until someone collects those values. With fork you have to call wait or waitpid to retrieve the process return values and clean up the zombie processes.

If you look at the very next section to where you copied the above code, "Waiting For A Thread To Exit", then you see them introduce the join() method, which is the threads equivalent of waitpid. There is no equivalent of wait(More's the pity.)

*wait. There is no equivalent of waitpid*. Corrected per ikegami's post++ below

So, to retrieve the return values from your 'zombie', 'peer' threads (there is no parent-child relationship), you have to call join, even if you discard the return values having done so.

Adding this to the example code, ensures that:

  1. The main thread lives long enough for the other threads to do what they need to do and exit.
  2. That those threads resources are cleaned up before the process exits, thereby avoiding the warning message you have been seeing.
use threads; $Param3 = "foo"; $thr1 = threads->new(\&sub1, "Param 1", "Param 2", $Param3); $thr2 = threads->new(\&sub1, @ParamList); $thr3 = threads->new(\&sub1, qw(Param1 Param2 Param3)); sub sub1 { my @InboundParameters = @_; print "In the thread\n"; print "got parameters >", join("<>", @InboundParameters), "<\n"; } $thr1->join; ## Wait for thread 1 to finish $thr2->join; ## Wait for thread 2 to finish $thr3->join; ## Wait for thread 3 to finish __END__ C:\test>junk2 In the thread got parameters >Param 1<>Param 2<>foo< In the thread got parameters >< In the thread got parameters >Param1<>Param2<>Param3<

There is also another method of avoiding the need to call join() on your threads. You can detach() them.

This is roughly equivalent to the *nix double forking daemonisation process, whereby the process forks twice, and the child terminates leaving the grandchild running. This breaks the parent-child-grandchild relationship and ensures that the parent doesn't have to hang around to clean up the grandchild.

With my apologies if this description is flawed. I've done very little with fork ever, and what I did do, was a long time ago. Hopefully, the analogy is still good

Eg.

use threads; $Param3 = "foo"; threads->new(\&sub1, "Param 1", "Param 2", $Param3)->detach; threads->new(\&sub1, @ParamList)->detach; threads->new(\&sub1, qw(Param1 Param2 Param3))->detach; sub sub1 { my @InboundParameters = @_; print "In the thread\n"; print "got parameters >", join("<>", @InboundParameters), "<\n"; } ## wait long enough to ensure that the threads ## will have completed before we let the main thread ## and the process die. sleep 10; __END__ C:\test>junk2 In the thread got parameters >Param 1<>Param 2<>foo< In the thread got parameters >< In the thread got parameters >Param1<>Param2<>Param3<

But note: it is still necessary to ensure that the main thread sticks around long enough for the other thread to finish. Using a sleep as above is not recommended for any real purpose. This makes detach() pretty useless as there is no way to query whether any detached threads are still running*.

*Even the extended forms of the list() class method in the updated cpan version still do not give access to this information.

I do not know of the existance of any better tutorial material for ithreads than perlthrtut. Whilst it would be possible to clean up the contents of that document--adding use strict; and join() etc. to the samples--via some judicious document patches, it would do little to improve its overall quality as a tutorial. It needs to be re-written so as to demonstrate usable techniques for working with ithreads--a set of design patterns if you will.

Whilst I have acquired enough experience of using ithreads to be able to write reasonable programs for most situations I've encountered where ithreads are applicable, my lack of a multi-cored/multi-processor testbed means that all my techniques and tests are strictly limited to a single processor environment. Trying to project that knowledge to cover usage in multi-processor environments--never mind other platforms--is just too difficult a mindware project to undertake.


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.
"Too many [] have been sedated by an oppressive environment of political correctness and risk aversion."

Replies are listed 'Best First'.
Re^2: Threads question
by ikegami (Patriarch) on Jun 29, 2007 at 14:53 UTC

    the join() method, which is the threads equivalent of wait. There is no equivalent of waitpid. (More's the pity.)

    That's backwards. join waits for a specific thread to end, just like waitpid($pid) waits for a specific process to end, and waitpid($pid, WNOHANG) is available as is_joinable. What's missing is the ability to wait for any thread to end (the equivalent of wait and waitpid(-1)).

    wait could be emulated as follows:

    use Time::HiRes qw( sleep ); sub wait_threads { for (;;) { my @joinable = threads->list(threads::joinable); if (@joinable) { return shift(@joinable)->join(); } sleep(0.010); } }