NAME

Thread::Shared -- Utilities to help manage thread shared memory.

SYNOPSIS

  use threads;
  use threads::shared;

  use Thread::Shared;
  use MyCustomClass;

  # Attempt to move an instance of a custom class into shared memory.
  my $obj = Thread::Shared::convert( MyCustomClass->new() );

  # Continue to call functions normally, now operating in shared memory!
  $obj->callMyMethod();

  # Get the actual shared hash out, which is necessary in order to pass it 
  # to another thread.
  my $hash = Thread::Shared::unwrap( $obj );

  # 
  # Lower-level utility functions:
  #

  # Recursively copy a hash or list into shared memory.
  my $hash = Thread::Shared::make_sharable({ 
        value1 => 1,
        value2 => 2
  });
  my $array = Thread::Shared::make_sharable([
        'value1',
        'value2'
  ]);

  # Wrap an shared array or hash in a tie()'d version which automatically
  # converts new members into sharable versions.
  my $magic = Thread::Shared::wrap( $hash );
  $magic->{value3} = { value4 => 4 };

  # Get the shared value back out.
  my $shared = Thread::Shared::unwrap( $magic );

  # Create an empty tie()'d hash.
  my $magic = Thread::Shared::convert({});

  # Determine whether a variable is sharable or one of our magic values.
  print "sharable"   if Thread::Shared::sharable($shared);
  print "ONE OF US!" if Thread::Shared::one_of_us($magic);

DESCRIPTION

Perl has a unique threading model, in that each thread gets a copy of all the data that was in the spawning interpretter --- it doesn't share memory with the other thread by default. This is more like using fork() than threading as used under most programming enironments. In fact, shared memory is really the only reason to use threads in environments where fork()'ing isn't a prohibitively expensive operation.

Perl does allow you to share memory between threads using the threads::shared module, however its use is far from convenient. threads::shared works by creating a seperate interpretter that all the threads have access to, and tie()'ing local thread variables to access this interpretter.

For example:

  use threads;
  use threads::shared;

  # create a shared hash
  my $data = &shared({});

  # add some data to it
  $data->{value1} = 1;
  $data->{value2} = 2;

This is all fun and happy, but you can only add references a shared data structure that is also shared. So:

  my $data = &shared({});

  # Won't work!  Kills the thread!
  $data->{value3} = { value4 => 4 };

  # You have to do this...
  $data->{value3} = &share({});
  $data->{value3}->{value4} = 4;

Now, see what you can do with Thread::Shared.

  use Thread::Shared;

  # Recursively copies the hash into a shared hash.
  my $data = Thread::Shared::make_sharable({
        value1 => 1,
        value2 => 2,
        value3 => {
                value4 => 4
        }
  });

  # Or, alternatively, use our special tied variables which
  # will automatically convert when encountering un-shared data.
  my $data2 = Thread::Shared::create_hash({
        value1 => 1,
        value2 => 2
  });
  # converts on the fly
  $data2->{value3} = { value4 => 4 };

  # We need the actual shared hash inorder to pass this to another thread.
  my $shared = Thread::Shared::unwrap($data2);

The convenience added here is minor. However, it is critical, if you are passing references into functions that expect normal hash or array references, not shared ones. This is especially important if you want one of your custom classes to be able to operate while stored in shared memory. If you class anywhere puts a non-shared array or hash onto $self, the thread will be killed.

We make this really simple:

  use Thread::Shared;
  use MyCustomClass;

  # create an instance of my custom class.
  my $obj = MyCustomClass->new();

  # convert the object to our custom tie()'ed hash.
  $obj = Thread::Shared::convert( $obj );

  # continue to call functions normally, now operating in shared memory!
  $obj->callMyMethod();

  # get the actual shared hash out in order to pass it to another thread.
  my $hash = Thread::Shared::unwrap( $obj );

FUNCTIONS

one_of_us $value

Returns an instance of Thread::Shared::Array or Thread::Shared::Hash if $value is one of our magic tie()'d references. Returns undef otherwise.

sharable $value

Returns true if this value is shared, one of our tie()'d references, or not a reference at all. Returns false otherwise.

wrap $value

Takes a shared array or hash and returns one of our magic tie()'d references.

unwrap $value

Returns shared data from one of our tie()'d references.

make_sharable $value

Returns a value that is capable to be added to a shared hash or array with data copied from $value.

convert $value

Creates one of our magic tie()'d references with data copied from some local variable. Will work perfectly fine with bless()'d references.

LIMITATIONS

Only really works for references of type ARRAY, HASH and bless references based on ARRAY. Circular references will break any of the functions that recurse. But, you can use recursive references in our tie()d objects just fine, so long as they are created as you go, and not convert()d in.