http://www.perlmonks.org?node_id=219141

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

I'm trying to access a blessed reference to a tied hash from a child thread and I'm going nuts in the process. Could someone shed some light on how to accomplish this?

At the point the "object" is created by the parent print $HS returns:

Win32::OLE=HASH(0x296b448)

and print Dumper(\$HS) returns:

$VAR1 = \bless( { 'plugin' => undef, 'ThreadID' => 1124, 'NoLog' => 0, 'hwnd' => 1900794, 'DebugMode' => 0, 'EventCount' => 2, 'DeviceCount' => 2, 'LastCommandSelected' => undef, 'SunRise' => '7:02 AM', 'SunSet' => '4:13 PM' }, 'Win32::OLE' );
So all is good up to this point. The parent then spawns a child and the same code run in the child thread produces:

Win32::OLE=HASH(0x437c94c)

Calling Dumper(\$HS) in the child crashes the application without any output to stderr/out. Even trying print $HS->{SunSet} causes the same crash.

This is all I want for Christmas.

-Nitrox

Replies are listed 'Best First'.
Re: Threads and object access
by djantzen (Priest) on Dec 11, 2002 at 19:26 UTC

    Disclaimer: this is based purely on reading, not real experience ;^)

    The model of threading in 5.8, ithreads, completely separates variables created in one thread from those in other threads. Much like forked processes, ithreads duplicate data rather than share it unless explicitly told to do so. I believe the reason for this approach is due to a vast quantity of Perl code having been written without consideration for thread safety. ithreads separate data to prevent race conditions when multiple threads manipulate the same object.

    So, I believe what you'll need to do is declare your variable $HS like:

    use threads::shared; my $HS : shared; # compile time declaration $HS = new Something();
    or
    use threads::shared; $HS = new Something(); share($HS);

    If this doesn't answer your question, perhaps you could post the relevant sections of code.

Re: Threads and object access
by Nitrox (Chaplain) on Dec 11, 2002 at 19:39 UTC
    Fever, I've already tried that route but unfortunately threads::shared doesn't support bless'd items.

    Using the second option:

    use threads::shared; $HS = new Something(); share($HS);
    Causes the reference to become fubar'd:

    $VAR1 = \bless( {}, 'Win32::OLE' );

    -Nitrox

      Ah, now I see it under the "Bugs" section in the docs: "bless is not supported on shared references. In the current version, bless will only bless the thread local reference and the blessing will not propagate to the other threads. This is expected to be implemented in a future version of Perl."

      What happens if you manually (re)bless the reference in each of the threads? Of course this is contingent upon it being possible that the reference itself (e.g., your Win32::OLE=HASH(0x437c94c)) can be shared, even though it is no longer associated with the package Win32::OLE.

      Update: I think I misunderstood the bug report. I believe it's referring to blessing after the variable has been created and shared; hence the phrase "blessing will not propagate". In some test code I'm successfully sharing blessed objects between threads, so I don't know why your Win32::OLE object is getting wiped out when you share it. How about posting some code?

Re: Threads and object access
by Nitrox (Chaplain) on Dec 11, 2002 at 21:22 UTC
    I'd love to post some example code for folks to test but this is part of a ActiveX Control module that I'm creating with PerlCtrl from the Perl Development kit. To make a long story short there is quite a bit of code needed just to get to this point. Add to that the need for the created DLL to be called by a 3rd party VB application. I'll try and create a high-level walkthru:

    After the VB application calls CreateObject() on my DLL it calls a subroutine in my code to establish the COM/callback objects. (shortened version below to give a general idea)

    1 sub RegCallback { 2 $CB = shift; 3 $HS = $CB->GetInterface(); 4 return; 5 }
    After calling this routine $CB contains Win32::OLE=HASH(0x2f1603c) but when trying to call Dumper() on $CB it errors with:

    Win32::OLE(0.1601) error 0x80004001: "Not implemented"

    $HS contains Win32::OLE=HASH(0x298ccdc) and Dumper() produces:

    $VAR1 = \bless( { 'plugin' => undef, 'ThreadID' => 1000, 'NoLog' => 0, 'hwnd' => 3932376, 'DebugMode' => 0, 'EventCount' => 2, 'DeviceCount' => 2, 'LastCommandSelected' => undef, 'SunRise' => '7:02 AM', 'SunSet' => '4:13 PM' }, 'Win32::OLE' );
    Adding share($CB) after line 2 allows the Dumper() call to return: $VAR1 = \bless( {}, 'Win32::OLE' ); but then line 3 errors with: Win32::OLE(0.1601): GetOleObject() Not a Win32::OLE object at /PerlApp/Win32/OLE/Lite.pm line 154.

    -Nitrox

Re: Threads and object access
by BrowserUk (Patriarch) on Dec 11, 2002 at 21:39 UTC

    From what I can make out, the problem is that Win32::OLE in common with many other modules, isn't yet threadsafe. There is some further discussion on this here and some discussion of what steps are required to do it here.

    Not a solution I'm afraid, but it may explain some of the problems.


    Okay you lot, get your wings on the left, halos on the right. It's one size fits all, and "No!", you can't have a different color.
    Pick up your cloud down the end and "Yes" if you get allocated a grey one they are a bit damp under foot, but someone has to get them.
    Get used to the wings fast cos its an 8 hour day...unless the Govenor calls for a cyclone or hurricane, in which case 16 hour shifts are mandatory.
    Just be grateful that you arrived just as the tornado season finished. Them buggers are real work.

Re: Threads and object access
by Nitrox (Chaplain) on Dec 11, 2002 at 22:34 UTC
    I was afraid of that BrowserUk.

    So for the time being can anyone suggest a viable alternative?

    The child thread simply sits in a while loop polling the serial port. When data is received the child then needs to be able to access $HS as is $HS->GotEvent(). Seeing as the child can't make the call directly what's the best way to instruct the parent to make the call. Or is it possible for a child thread to explicitly call a subroutine in the parent thread instead of it's own?

    -Nitrox

      One mechanism would be to use signals or semaphores and a shared data buffer.

      The child thread get its data, puts it into the shared buffer and then signals (semaphores) when it has put something in the buffer to process.

      (Win32::Semaphore is one possibility, but there is Threads::Semaphore in 5.8, but I am being a luggard and haven't got around to upgrading yet).

      You don't say what the parent thread is doing, but it would need to check (with timeout if necessary) for the semaphore and then take the appropriate action on behalf of the child.


      Okay you lot, get your wings on the left, halos on the right. It's one size fits all, and "No!", you can't have a different color.
      Pick up your cloud down the end and "Yes" if you get allocated a grey one they are a bit damp under foot, but someone has to get them.
      Get used to the wings fast cos its an 8 hour day...unless the Govenor calls for a cyclone or hurricane, in which case 16 hour shifts are mandatory.
      Just be grateful that you arrived just as the tornado season finished. Them buggers are real work.

        The parent thread is pretty usless and is held in a "by-call state" by the PerlCtrl internals, which is why I was forced to spawn a child to do my polling.

        -Nitrox