Jerry D. Hedden wrote:
Dean Arnold wrote:
I've been pouring over the p5p archives trying to find
what the subject p5p summary item is about, but wo/ any luck.
Can someone point out the relevent thread title, or maybe
summarize what "threads::shared could share aggregates
properly with only Perl level changes to shared.pm"
means ?
It means that something like this would DWIM:
my $x : shared;
$x = [ { 'complex' => 'aggregate' }, [ qw/ currently not sharable / ] ];
<snip/>
Thread::Queue has the Perl code needed for making 'complete'
shared clones of data structures (i.e., all parts whether
shared or not are cloned). Tweaking it to not clone already
shared portions is trivial.
I see someone's been busy ;^)
Alas, there's one catch that the current T::Q implementation
doesn't cover: recursive structures:
(Using AS Perl 5.8.8, WinXP, T::Q 2.06)
use strict;
use warnings;
use threads;
use threads::shared;
use Thread::Queue;
use Data::Dumper;
my $q = Thread::Queue->new();
my $x = [ { 'complex' => 'aggregate' },
[ qw/ currently not sharable / ] ];
my $thrd = threads->create(\&receiver, $q);
$q->enqueue($x);
$thrd->join();
print "*** non-recursive OK\n";
#
# Make it a recursive structure
# (!!! this will choke)
#
push @$x, $x;
$thrd = threads->create(\&receiver, $q);
$q->enqueue($x);
$thrd->join();
print "*** recursive OK\n";
sub receiver {
my $q = shift;
my $data = $q->dequeue();
print "** in child:\n", Dumper($data), "\n";
}
The 2nd part emits a bunch of
"Deep recursion on anonymous subroutine at C:/Perl/lib/Thread/Queue.pm line 181"
warnings and then hangs.
While I agree that recursive structures should be discouraged, and don't
expect T::Q (or threads::shared, ftm) to try to trap them, the T::Q POD
probably needs to include a warning about it. And in the case of queueing
blessed objects, I'd expect instances of circular refs between objects
not to be uncommon.
FWIW: I had looked into this issue for Thread::Queue::Duplex and
Thread::Apartment, and punted the deepcopy clone to Storable instead
because of the circular ref issue.
OTOH, if a bitflag could be grabbed
somewhere to do a mark/sweep, this might be solvable
Or maybe using a fieldhash to key the original ref thats
being cloned, do a quick lookup, and if it exists, then skip it
ala testing for shared-ness ? kinda slow, and maybe a memory pig
for deep structures, but should solve the issue.
Then we just need a tie-in with the assignment operator. Or
perhaps we could just provide a function:
$y = shared_clone($x);
Would an assignment op overload work ?
I.e., if the LHS was already shared(), then the = overload
would do the deepcopy ? Or would that break the
XS tie/magic side of the code ?
I guess it wouldn't break *if* the clone operation gets pushed
down to XS; then the STORE operation just detects the
value as an unshared ref (as it already does), and performs
the deepcopy. At which point some add'l optimization (e.g.,
grabbing the global lock once for the entire copy operation)
could be applied.
At which point, turning an existing populated hash/array
into a shared variable could also be updated to preserve the contents.
- Dean