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

I am trying to use threads inside of a perl object and it isn't working. Here is the code:
120 sub _openFDCObject 121 { 122 my $self = shift; 123 my $swObject = shift; 124 my $switch = shift; 125 my $fdcObject = FosDataCapture->new($log, $swObject); 126 return ($fdcObject, $switch); 127 } 128 129 sub getFDCObjects 130 { 131 my $self = shift; 132 my %fdcObjectHash; 133 my @threadQueue; 134 my %switches = $self->getSwitches(); 135 for my $switch (keys %switches) 136 { 137 #my $fdcObject = $self->_openFDCObject($switches{$switch}, + $switch); 138 my $swObject = $switches{$switch}; 139 my $thread = threads->create(\$self->_openFDCObject($swObj +ect,$switch)); 140 push(@threadQueue, $thread); 141 #$fdcObjectHash{$switch} = $fdcObject; 142 } 143 foreach my $thread (@threadQueue) 144 { 145 my ($fdcObject, $switch); 146 ($fdcObject, $switch) = $thread->join(); 147 $fdcObjectHash{$switch} = $fdcObject; 148 } 149 return %fdcObjectHash;
What I don't know is how I format line 139 to call the subroutine that is part of the object. I have tried the following:
my $thread = threads->create(\$self->_openFDCObject($swObject,$switch) +); my $thread = threads->create(\$self->_openFDCObject,$swObject,$switch) +; my $thread = threads->create($self->_openFDCObject,$swObject,$switch); my $thread = threads->create(&_openFDCObject,$swObject,$switch);
The first one above does run, but I don't see any threading happening. The other invocations don't pass $swObject and $switch to the subroutine _openFDCObject. Please let me know if you need any further information. Thanks

Replies are listed 'Best First'.
Re: How do I used a threaded subroutine inside a perl object
by BrowserUk (Patriarch) on Jul 03, 2013 at 05:55 UTC

    Enable strict and warnings and Perl itself will tell you that this is wrong:

    my $thread = threads->create(\$self->_openFDCObject($swObject,$switch) +)

    threads->create() requires a code reference as its first argument and you are passing a reference to the return value of a method call. (Which given that the method returns a list of two items, means I cannot actually guess what it is that you are passing to create(), but I do know you ought to be seeing an error message of the form:Thread 1 terminated abnormally: Not a CODE reference)

    But before we get into how you might correct the syntax and semantics issues, why are you trying to run that method in a thread? How long does it take to create this new FosDataCapture() object?

    Let me tell you that your threading "design" will not (ever) work as is, and for so many reasons that it is hard to know where to start. Your understanding of threads is either so limited or wrong that I really don't know how to begin to help you. But if you answer the above question first, we might get some where


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.

      Hi BrowserUK, This is my first try at threads so you are right that my understanding is currently limited.

      Inside the method I am trying to call, I am creating a new FosDataCapture Object. During the _init phase of this object it gathers a bunch of data via telnet from the swObject (this is a fibre channel switch). This process can take 60 seconds for switch and I will have over 30 switches when running in production. Without threading, this portion of the code will take too long to run. I think that answers the first two questions.

      You stated that threads->create() requires a code reference. According to the threads link you posed it states the following:

      --------- $thr = threads->create(FUNCTION, ARGS) This will create a new thread that will begin execution with the specified entry point function, and give it the ARGS list as parameters. It will return the corresponding threads object, or undef if thread creation failed. FUNCTION may either be the name of a function, an anonymous subroutine, or a code ref -------------

      With this definition, my first thought my call should be like this:

      $thread = threads->create($self->_openFDCObject,$swObject,$switch);

      When I called it like this, $swObject and $switch do not get passed into the function. So I tried a few other structures to see what might work since I could find no examples of how to use threads inside an object when calling a function inside the object.

      Any further help would be greatly appreciated. Thanks

        You could try it this way:

        $thread = threads->create( \&_openFDCObject, $self, $swObject, $switch + );

        Which should work in as much as the thread should start and run the method, but after that I suspect things will not the way you are expecting them to.

        But frankly, it would be too hard to explain why to you, you'll need to learn by your mistakes.


        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
Re: How do I used a threaded subroutine inside a perl object
by roboticus (Chancellor) on Jul 03, 2013 at 01:23 UTC

    adamcpfeiffer:

    In a situation like this, I'd suggest using a closure that holds your object reference.

    my $thing = new thing(); my $closure = sub { $thing->stuff_to_do(); }; my $thread = threads->create($closure);

    ...roboticus

    When your only tool is a hammer, all problems look like your thumb.

      Why?  threads->create( $thing->can('stuff_to_do'), $thing );
      I tried to use a code reference, but that failed as well. One difference I had to use is that I can't call object->new() outside of the closure as the new calls _init which is what I need to have run in a thread. I can change the object so new just creates a new object and then call _init in the closure if that would help.
      sub getFDCObjects { my $self = shift; my %fdcObjectHash; my @threadQueue; my %switches = $self->getSwitches(); for my $switch (keys %switches) { #my $fdcObject = $self->_openFDCObject($switches{$switch}, $sw +itch); my $swObject = $switches{$switch}; my $threaddo = sub { my $self = shift; my $swObject = shift; my $switch = shift; my $fdcObject = FosDataCapture->new($log, $swObject); return ($fdcObject, $switch); }; my $thread = threads->create($threaddo,$swObject, $switch);