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
- re-bless the object instance into each thread which avoid the cross-thread method calling problem.
- You store references to shared instance variables within the hash object and dereference them to read or modify them.
- 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.
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...
- You create a pool of "resource" objects
whose members are all shared
- you pass the objects to the threads
when they are created
- 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... | [reply] |
|
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.
| [reply] |
|
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...
| [reply] |
|
|
|