Beefy Boxes and Bandwidth Generously Provided by pair Networks
Think about Loose Coupling
 
PerlMonks  

Re: How can I unshare something?

by BrowserUk (Pope)
on Jul 19, 2008 at 00:14 UTC ( #698760=note: print w/ replies, xml ) Need Help??


in reply to How can I unshare something?

Like other responses, I'm confused by your description of what you are trying to do. You say:

Why would I want to do this, people ask? Well, I can't add un-shareable values to shared hashes (objects), which I, sadly, need to do.

But that seems to be the exact opposite of what you are asking for? Ie. You say you can't copy unshareable values into a shared hash, but you're asking how to 'unshare' shared data?

To answer the question you've asked--how to unshare, shared data--delete it. Once it is deleted by one thread, no thread can access it.

If you need one thread to continue to have access, duplicate it (Clone would work) into a thread local, none shared copy, and then (deep) delete the shared copy. You might need something like (Rmap or Data::Diver to ensure that if another thread has taken a reference to some subset of the original data structure (I'm assuming this is what you meant by "blob"), that it will no longer have access to the data. Of course, if it has already taken a copy (shared or otherwise), you will not be able to prevent it from continuing to access the copy!

But, I suspect, that that isn't what you meant to ask. My suspicion is that you have a non-shared, complex, data-structure, and what you want to do is transfer a copy of to another thread. And you are falling foul of the threads::shared::share() inability to share nested data structures?

If this is the case, then you need to traverse the data structure manually and share then copy nested elements individually and recursively. You might find this (lightly tested and unpublished...it still has limitations) module useful:

{ package shareDeep; ## threads::shareDeep is the intended name for +release... use strict; use warnings; use threads; use threads::shared qw[ bless ]; use Carp qw[cluck carp]; use Scalar::Util qw[ readonly reftype blessed ]; require Exporter; our @ISA = 'Exporter'; our @EXPORT = qw[ shareDeep ]; our $TRACE = 0; *_trace = $TRACE ? sub{ my $fmt = shift; warn( sprintf "%3d %s(%d): %s\n", threads->self->tid || 0, __FILE__, __LINE__, $fmt, @_ ); } : sub(){ 0 }; sub _invalid { warn( "Can't share '$_[ 0 ]'; substituting as placeholder\ +n", ); return "$_[ 0 ]"; } sub getType { blessed( $_[ 0 ] ) ? reftype( $_[ 0 ] ) : ref( $_[ 0 + ] ); } my %do; %do = ( '' => sub { _trace( "VALUE: @_ : " . getType( $_[ 0 ] ) ); $_[ 0 ] }, SCALAR => sub { _trace( "SCALAR: @_ : " . getType( $_[ 0 ] ) ); my $scalar :shared = ${ $_[ 0 ] }; \$scalar }, HASH => sub { _trace( "HASH: @_ : " . getType( $_[ 0 ] ) ); my $in = shift; my %hash :shared = map { $_ => $do{ getType( $in->{ $_ } ) }->( $in->{ $_ } ) } keys %{ $in }; \%hash; }, ARRAY => sub { _trace( "ARRAY: @_ : " . getType( $_[ 0 ] ) ); my @array :shared = map{ $do{ getType( $_ ) }->( $_ ) } @{ $_[ 0 ] }; \@array; }, REF => sub { _trace( "REF: @_ : " . getType( $_[ 0 ] ) ); my $ref :shared = $do{ getType( ${ $_[ 0 ] } ) }->( ${ $_[ + 0 ] } ); \$ref }, GLOB => \&_invalid, LVALUE => \&_invalid, CODE => \&_invalid, Regexp => \&_invalid, ); readonly( \%do ); sub shareDeep { my( $in ) = shift; return my $out :shared = $do{ getType( $in) }->( $in ); } } return 1 if caller; package main; use threads; use threads::shared qw[ bless ]; use Data::Dump qw[ pp ]; $Data::Dump::MAX_WIDTH = 500; shareDeep->import; sub test{ print "test sub @_" }; my %test = 1 .. 10; my $rSharedHash = shareDeep( \%test ); pp $rSharedHash; my @test = 1 .. 10; my $rSharedArray = shareDeep( \@test ); pp $rSharedArray; my $test = 'test'; my $rSharedScalar = shareDeep( \$test ); pp $rSharedScalar; my $rSharedRef = shareDeep( \\$test ); pp $rSharedRef; $rSharedRef = shareDeep( \\\\\\\\\\$test ); pp $rSharedRef; my $lvalue = \substr( 'fred', 1, 2 ); my $sharedLvalue :shared = shareDeep( $lvalue ); pp $sharedLvalue; my $glob = do{ local *GLOB; \*GLOB }; my $sharedGlob :shared = shareDeep( $glob ); pp $sharedGlob; my %hash = ( array => \@test, hash => \%test, ); my $nested :shared = shareDeep( \%hash ); pp $nested; my $blessed :shared = shareDeep( threads::shared::bless [], 'fred' ); print pp $blessed;

It exports a single entrypoint, shareDeep() that will return (by reference) a fully shared duplicate of the structure passed in. (Also by reference.)

It currently issues a warning for any unshareable elements contained in the structure to be copied, and substitutes a placeholder. Probably not the best design choice, but useful while I decide if there is a better approach.

The embedded tests should serve as a guide to usage.


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.


Comment on Re: How can I unshare something?
Select or Download Code
Re^2: How can I unshare something?
by renodino (Curate) on Jul 19, 2008 at 01:34 UTC
    ...or the OP can use the shiny new threads::shared::shared_clone(), which does the same thing ;^>

    Perl Contrarian & SQL fanboy

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://698760]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others studying the Monastery: (16)
As of 2014-10-24 16:25 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    For retirement, I am banking on:










    Results (133 votes), past polls