It is a fundamental law of ... blogging that updates come in spurts? I hacked (just a little teensy weensy tiny bit) and we're back in business with the 5.8 threading. Apparently, the distinction between joinable and still waiting has been removed with the recent threads upgrades. I don't have enough free brain cells to grok this, but the punch line is ... well, look at the finished version of 'threadbossworker.pl' for yourself, and compare it to http://www.radkeland.org/boss-worker-threaded-model-implemented-perl if you're masochistic, and ... grin, and hope it works for you. The short bit is that arguments to thread->list() are now completely irrelevant.
#!/usr/bin/perl -w
#
# threadbossworker.pl
#
# Copyright 2008 Joshua Radke (josh at radkeland dot org)
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License (version 2) as
# published by the Free Software Foundation.
#
# This program is a demonstration (simple scaffold) for a boss/worker
# threaded program. It uses semaphores to control the number of worker
# threads allowed. It uses a general cleanthreads() routine to gather
# the results from finished threads. The cleanthreads routine takes a
# reference to a function to determine what to do with the harvested
# threads.
#
# These are the minimum needed to implement a semaphore managed
# threading program.
use strict;
use threads;
use Thread::Semaphore;
# Cleanthreads harvests and dispatches the return values of the worker
# threads (detail with the actual function). Idleworker hangs out
# awhile, and returns its original value untouched. Note that
# idleworker needs to be thread aware (increment and decrement the
# semaphore). Printreturn prints the value of whatever is passed to
# it, with a newline appended.
sub cleanthreads($$@);
sub idleworker($);
sub printreturn($);
my $maxthreads = 5;
my $sem = new Thread::Semaphore($maxthreads);
for my $i (1 .. 10) {
threads->create(\&idleworker, $i) or die "Unable to create thread";
cleanthreads(0, \&printreturn, "foo");
}
cleanthreads(1, \&printreturn, "foo");
exit(0);
# Cleanthreads is the interesting workhorse of the threading model. It is
# called like this:
# cleanthreads(<mode>, <action function>, <list of other arguments
# for action function> )
# Mode = 0 or 1. The meanings are:
# 0: Find all joinable threads , and join/process the return value.
# Do not return unless there is at least one semaphore available.
# 1: Clean all threads but the parent before returning.
sub cleanthreads($$@) {
my $mode = shift @_;
my $func = shift @_;
my @othervals = (defined($_[0])) ? (@_) : (undef);
my @thrlist;
# Get our list of threads to join.
@thrlist = threads->list();
# And do the deed. I had previous reservations, but had no idea what
# I was concerned about. Progress sometimes (regretably) hides the true
# reality that should have been uncovered, but remains buried to the
# author's incompetence.
foreach my $thr (@thrlist) {
&$func($thr->join(), @othervals);
}
return;
}
sub idleworker($) {
$sem->down;
my $retval = shift @_;
sleep 2;
$sem->up;
return $retval;
}
sub printreturn($) {
print "$_[0]\n";
return;
}