in reply to How to pass a module method by reference to Thread?

You could also do this (rather dirtily :) like this:

my $th = new Thread( \&Another::Module::run, $p );

but don't do it either way! It will not do what you think it will.

You have to remember that 2 threads means two independant interpreters. All variables created in one interpreter, including even globals like $/ and $!, are completely independant of the same named variable in the other interpreter. This can be demonstrated by

D:\Perl\test>perl58 -de1 Loading DB routines from perl5db.pl version 1.19 Editor support available. Enter h or `h h' for help, or `perldoc perldebug' for more help. main::(-e:1): 1 DB<1> use threads DB<2> $t=threads->new( sub{ $\ = "\nCRLF\n"; print 'test'; print 'by +e'; return; } ) DB<3> test CRLF bye CRLF DB<3> print 'Hello' DB<4> Hello DB<4> $t->join Scalars leaked: 1 DB<5> q D:\Perl\test>
Now, when you pass the object $p (which is really a blessed hash reference) into the run() method, either implicitly via grantms method or explicitly through mine, the threads module has to create a copy of the variable in the second threads context. And what you get is a copy of the hash as it was at the time thread is created, and $p is a completely different reference, blessed into a completely different copy of the Another::Module. That is to say, $p in the main thread and $self that arrives in the run() method are different references, to different hashes, blessed into different copies of the Another::Module. Any changes made to one, will not effect the other and vice versa. To demonstrate, this piece of code
#! perl -slw use strict; package Another::Module; use threads; sub new{ my $class = shift; return bless {@_}, $class; } sub run { my $self = shift; print $self, '|', \&Another::Module::run; print threads->self()->tid, ' : ', join' ', %{ $self }; sleep 2; $self->{'a new element'} = 'added in the second thread'; sleep 2; print threads->self()->tid, ' : ', join' ', %{ $self }; } package main; use threads; my $p : shared = Another::Module->new( some=>1, initialisation=>'data' + ); print $p, '|', \&Another::Module::run; print threads->self()->tid, ' : ', join' ', %{ $p }; my $t = threads->new( \&Another::Module::run, $p ); print threads->self()->tid, ' : ', join' ', %{ $p }; $p->{'a new element'} = 'added in the main thread'; # Dirty. For demo +only print threads->self()->tid, ' : ', join' ', %{ $p }; sleep 10; # Give the second thread a chance to end. print threads->self()->tid, ' : ', join' ', %{ $p }; $t->join;

Produces this output

E:\perl58-rc3\test>test.pl3 Another::Module=HASH(0x8823dc)|CODE(0x16381cc) 0 : initialisation data some 1 0 : initialisation data some 1 0 : initialisation data a new element added in the main thread some 1 Another::Module=HASH(0x166cde4)|CODE(0x166c7f0) 1 : initialisation data some 1 1 : initialisation data a new element added in the second thread some +1 0 : initialisation data a new element added in the main thread some 1

As you can see, not only is the address of the blessed hash different in the main thread (Another::Module=HASH(0x8823dc)) and the second thread (Another::Module=HASH(0x166cde4)), but so is the address of the run() method. Main:CODE(0x16381cc) -v- second:CODE(0x166c7f0).

The code also shows that changes made to the object (hash) in the main thread do not effect the object in the second thread and vice versa.

Your first reaction may be to thing to load threads::shared and share the object, but this doesn't work. If you try it, you will get the error message

Invalid value for shared scalar at E:\perl58-rc3\test\test.pl3 line 26.

This is because threads::shared will detect that the scalar is a blessed ref, which is explicitly precluded in the POD

bless is not supported on shared references. In the current version, b +less will only bless the thread local reference and the blessing will + not propagate to the other threads. This is expected to be implement +ed in a future version of Perl.

The only reason you can get away with using either means of invoking methods on an object created in one thread in the context of another thread is because the threads module knows that it must copy any existing data from the main thread into the contexts of the new threads when they are created. It also knows that it must bless any blessed references that are copied into the copies of the package into which they were blessed, but in the context of the new thread.

In the process, it has created to independant instances of the object and ne'er the twain shall meet.

The upshot is that if you want to use objects within a thread, you can do so, so long as it is notyour intent to share thse objects between threads. If this is your intent, the you should not create the object in the main thread and then pass it to the other thread, but you should create that object in the other thread.


Examine what is said, not who speaks.
"Efficiency is intelligent laziness." -David Dunham
"When I'm working on a problem, I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong." -Richard Buckminster Fuller


Replies are listed 'Best First'.
Re: Re: How to pass a module method by reference to Thread?
by castaway (Parson) on Jun 22, 2003 at 06:48 UTC
    This may be all very correct, but please note the questioner is using 'Thread' and not 'threads', which means the 5.005 threads, and not ithreads, which is a different kettle of fish entirely, AND shares ALL variables per default between the threads!

    Looking at my own 5.005 Threads code, I seem to be using/sharing objects fine between threads there.. So thats one advantage of still using the old threads :)

    C.

      How right you are++. I completely missed that minor point.

      I'm so caught up trying to get my own stuff going with ithreads, and this looked so like one of my own early flounderings with them, that I responded to completely the wrong question. :(


      Examine what is said, not who speaks.
      "Efficiency is intelligent laziness." -David Dunham
      "When I'm working on a problem, I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong." -Richard Buckminster Fuller