Posted on 2010-07-30 22:55:10.333033-07 by patha
block until one thread is joinable?
Hi,

I want to be able to do something similar to:

sub select_one_to_join () { for (;threads->list(threads::joinable) == 0; sleep(0.01)) { } return (threads->list(threads::joinable))[0]; }

Is this possible without using polling+sleep?

As a different request, I noticed that it would be nice to register (at thread create time) a callback function that is invoked to handle the result (in parent context) when join is called.

As background context, here is the code I have used:

if (defined $optsl{'jobs'}) { if ($^V lt v5.8.9) { require Parallel::ForkManager; my $pm = new Parallel::ForkManager($optsl{'jobs'}); foreach my $num (@testcases_to_run) { # do the fork, parent continues with next iteration $pm->start and next; # handle_result should run in parent context for best # result. However, it is only possible to pass 8 bits as # result value (through exit()) from the child # and build_run_test return much more data. handle_result(build_run_test($test_matrix[$num])); $pm->finish; # do the exit in the child process } $pm->wait_all_children; } else { use threads; # version 1.34 or above is required use Time::HiRes 'sleep'; # all thread results are processed with handle_result sub join_and_handle_result ($) { my ($thr) = @_; handle_result($thr->join()); } sub select_one_to_join () { for (;threads->list(threads::joinable) == 0; sleep(0.01)) { } return (threads->list(threads::joinable))[0]; } sub join_some ($) { my ($limit) = @_; for (; threads->list() > $limit; ) { join_and_handle_result(select_one_to_join()); } } $total_result = OK; foreach my $num (@testcases_to_run) { join_some($optsl{'jobs'} - 1); threads->create({'context' => 'list'}, 'build_run_test', $test_matrix[$num]); } join_some(0); } } else { $total_result = OK; foreach my $num (@testcases_to_run) { handle_result(build_run_test($test_matrix[$num])); } }
Direct Responses: 12859 | 12861 | Write a response
Posted on 2010-07-31 08:43:54.483125-07 by patha in response to 12858
Re: block until one thread is joinable?
This is perhaps better code (replacing select_one_to_join and join_some):
sub join_any () { for (;;sleep(0.01)) { my @thrs = threads->list(threads::joinable); return $thrs[0]->join() if (@thrs > 0) } } sub limit_threads ($) { my ($limit) = @_; for (; threads->list() > $limit; ) { handle_result(join_any()); } }
Direct Responses: 12860 | Write a response
Posted on 2010-07-31 16:23:28.384128-07 by jdhedden in response to 12859
Re: block until one thread is joinable?
My recommendation is to set up a Thread::Queue. Threads that are done working would then put their thread ID on the queue before terminating. The main thread would then monitor the queue for any IDs, and then using the ID, would join with the thread and process its results. The 'threads' module on CPAN has a 'examples' directory with two scripts that do just this.
Direct Responses: Write a response
Posted on 2010-07-31 16:38:17.354361-07 by jdhedden in response to 12858
Re: block until one thread is joinable?
You asked: As a different request, I noticed that it would be nice to register (at thread create time) a callback function that is invoked to handle the result (in parent context) when join is called.

This can easily be done by creating a hash to register callbacks based on thread IDs:
my %callbacks; my $thr = threads->create(...); $callback{$thr->tid()} = \&callback;
Then wherever you monitor the thread termination queue, you get the ID of the completed thread and invoke the callback:
my $id = $q->dequeue(); $callback{$id}->($id);
The callback then joins with the thread and completes the work:
sub callback { my $id = $_[0]; my $thr = threads->object($id); my $result = $thr->join(); ... }
Direct Responses: Write a response
Perl Weekly newsletter
A free weekly newsletter for people who are busy to read all the blogs. click here to check it out.