thai has asked for the wisdom of the Perl Monks concerning the following question:

Hi there,
Here is the partial of my code:
----------------------------------------------------
use Thread; use Another::Module; # This module has method run() my $p = new Another::Module(some_args); my $th = new Thread(\$p->run); # Line: 88 $th->detach();
----------------------------------------------------
I had an error say:
thread failed to start: Not a CODE reference at line 88

Clearly, that if "run" method is a local subroutine then it works.

My question is: Is that line 88 syntax correct?
Can I use a subroutine from another module when calling:
new Thread(\&Another::module->subroutine())?

Thanks in advance

Replies are listed 'Best First'.
Re: How to pass a module method by reference to Thread?
by grantm (Parson) on Jun 21, 2003 at 23:21 UTC

    You can't take a reference to a method call. But you could try this:

    my $th = new Thread( sub { $p->run } ); # Line: 88
      sure you can:
          my $method_ref = $this->can("name_of_method_call");
          
          #...later...
          
          $method_ref->( $this, @args );
      
Re: How to pass a module method by reference to Thread?
by BrowserUk (Patriarch) on Jun 22, 2003 at 02:58 UTC

    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


      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