Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl Monk, Perl Meditation
 
PerlMonks  

Re: Passing objects between threads...any solutions? (shared objects)

by BrowserUk (Patriarch)
on Jun 10, 2005 at 01:25 UTC ( [id://465380]=note: print w/replies, xml ) Need Help??


in reply to Passing objects between threads...any solutions ?

How brave are you?

The code below uses a technique I've been playing with to share two instances of an object between 10 threads that each modify whichever instance they get 100 times before terminating. The main thread then displays the values which will be whatever values were last set into them by whichever thread accessed them last. The program runs reliably under 5.8.4 on my (single cpu) system with no idication of errors, traps or memory leakage.

#! perl -slw use strict; use threads; use threads::shared; package Dummy; sub new { my $sem : shared; my $this : shared = 12345; my $that : shared = 'fred'; my $theOther : shared = 3.141592653; return bless { sem => \$sem, this => \$this, that => \$that, theOther => \$theOther, }, $_[ 0 ]; } sub this : lvalue { my $self = shift; lock ${ $self->{ sem } }; ${ $self->{ this } }; } sub that : lvalue { my $self = shift; lock ${ $self->{ sem } }; ${ $self->{ that } }; } sub theOther : lvalue { my $self = shift; lock ${ $self->{ sem } }; ${ $self->{ theOther } }; } sub combo { my $self = shift; lock ${ $self->{ sem } }; ${ $self->{ that } } = "[ ${ $self->{ this } } : ${ $self->{ theOt +her } } ]"; } package main; sub thread { Win32::Sleep rand( 1000 ); my( $obj ) = @_; bless $obj, 'Dummy'; for ( 1 .. 100 ) { Win32::Sleep rand( 1000 ); print threads->tid, ': ', join ' : ', $obj->this, $obj->that, + $obj->theOther; $obj->this = threads->tid; $obj->that = '' . threads->tid; $obj->theOther = rand 1000; $obj->combo; print threads->tid, ': ', join ' : ', $obj->this, $obj->that, + $obj->theOther; } } my @objs = map{ new Dummy } 1 .. 2; my @threads = map{ threads->create( \&thread, $objs[ rand 2 ] ) } 1 .. + 10; $_->join for @threads; bless $_, 'Dummy' for @objs; print 'Back in main: ', join ' :', $_->this, $_->that, $_->theOther for @objs;

The basis of idea is that

  1. re-bless the object instance into each thread which avoid the cross-thread method calling problem.
  2. You store references to shared instance variables within the hash object and dereference them to read or modify them.
  3. You embed a reference to a shared object that is used as a semaphore (via lock) into each instance and lock this in each method before accessing the instance data.

I haven't had the facilities to test this on a multi-processor system, but I think it should be safe. Any feedback you can let me have would be much appreciated.


Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
"Science is about questioning the status quo. Questioning authority".
The "good enough" maybe good enough for the now, and perfection maybe unobtainable, but that should not preclude us from striving for perfection, when time, circumstance or desire allow.
  • Comment on Re: Passing objects between threads...any solutions? (shared objects)
  • Download Code

Replies are listed 'Best First'.
Re^2: Passing objects between threads...any solutions? (shared objects)
by kimanaw (Beadle) on Jun 10, 2005 at 03:32 UTC
    OK, lemme see if I follow the plot...

    1. You create a pool of "resource" objects whose members are all shared

    2. you pass the objects to the threads when they are created

    3. on creation, the thread dup's the resource object, thereby inheriting the shared members (albeit inside a new version of the object)

    My only wrinkle is that I'm using a thread pool...but if I use a resource pool, I can instantiate the resource pool into each thread in the thread pool at startup, so I just need to add some scalar ID to each resource thread that can be used to direct a thread to whichever resource object to fiddle with.

    Hmmm, intriguing...

    I will definitely give it a shot. It may be a bit of a memory pig, but actually may also help limit the chances for memory leaks (kinda like building all Perl/Tk widgets at startup, and withdrawing til needed...kills memory leak bugs DEAD!)

    PS. I do in fact have a dual CPU system (running Win2K); don't know when I'll get a chance to test this on it, (lots more code to implement/test before that), but I definitely owe you a barley pop...

    And here's hoping Ponie solves this issue...

    Many thanks...

      but I definitely owe you a barley pop...

      If you could post (on your scratchpad) the results from running my test code on your dual processor and /msg me I'd be very happy.

      1. You create a pool of "resource" objects whose members are all shared

      2. ...

      3. ...

      That's not quite right, but I'm a too tired to correct it now. Check back later/tomorrow (before you start coding based on this) and I'll try to clarify.


      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
      "Science is about questioning the status quo. Questioning authority".
      The "good enough" maybe good enough for the now, and perfection maybe unobtainable, but that should not preclude us from striving for perfection, when time, circumstance or desire allow.
        RE: dual CPU tests: will do, esp. since...

        RE: pool of resource objects

        I've managed to take your notion and run w/ it, and may even CPAN a module in the near future to do what I need, namely, create a ResourcePool object that acts as a pool/factory for objects of a specified type. Each thread gets the ResourcePool by default when the thread clones everything at create() time. Then the thread can either allocate() a fresh resource object from the ResourcePool, or use a scalar ID to get() an existing object. The thread either explicitly free()'s the object, or the resource's DESTROY() frees the object back to the pool when it goes out of scope (note the free() may only mean it is disassociated from the thread, but remains allocate()'d by other threads).

        Thanks for getting me headed in the right direction...

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others having a coffee break in the Monastery: (4)
As of 2024-04-19 23:26 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found