develooper Front page | perl.perl5.porters | Postings from November 2007

YATSB (yet another threads::shared bug)

Thread Next
From:
Jerry D. Hedden
Date:
November 9, 2007 09:19
Subject:
YATSB (yet another threads::shared bug)
Message ID:
1ff86f510711090918ja5c0f08wff58d1f19666a3fa@mail.gmail.com
Dave, if you have the time, would you give some thought to
the bug below?  It seems that all the other threads::shared
bugs I had previously found have been fixed, but this one
still persists.

It starts with a shared object that is attached to a shared
scalar.  Inside a thread, the object is first modified, and
then replaced with a new one.  When the thread terminates,
however, the original object seems to still be in place.
Then the bug just goes away.

Here's the code (it's attached as well):

    #!/usr/bin/perl

    use strict;
    use warnings;

    package Foo; {
        use threads;
        use threads::shared;

        my $ID : shared = 1;   # Incremented with each new object

        sub new
        {
            # Anonymous scalar with an internal ID
            my $obj = \do{ my $scalar = $ID++; };
            # Make it shared
            share($obj);
            # Make it an object
            return (bless($obj, 'Foo'));
        }
    }

    package main;

    use threads;
    use threads::shared;

    use Test::More 'no_plan';

    MAIN:
    {
        my $obj : shared;
        $obj = Foo->new();

        # Check the object - this part is okay
        print("       Main: Object ID $$obj\n");
        is($$obj, 1, "Main: Object ID $$obj");
        print("\n");

        # Now play with the shared object inside a thread
        threads->create( sub {
                # Check the object inside the thread - this part is okay
                print("       Thread: Object ID $$obj\n");
                is($$obj, 1, "Thread: Object ID $$obj");
                print("\n");

                # Modify object's 'ID' - this works
                $$obj = 10;
                print("       Thread: Object ID $$obj\n");
                is($$obj, 10, "Thread: Object ID $$obj");
                print("\n");

                # Replace the object with a new one - this works
                $obj = Foo->new();
                print("       Thread: Object ID $$obj\n");
                is($$obj, 2, "Thread: Object ID $$obj");
                print("\n");

            } )->join();

        # Check the object - it should be the new one from the thread,
        #   but it isn't!
        print("BUG!   Main: Object ID $$obj (should be 2)\n");

        # Wait a minute - suddenly the object reverts!
        #   What's going on here?
        is($$obj, 2, "Main: Object ID $$obj");
        print("       Main: Object ID $$obj\n");
    }
    exit(0);

It produces:

           Main: Object ID 1
    ok 1 - Main: Object ID 1

           Thread: Object ID 1
    ok 2 - Thread: Object ID 1

           Thread: Object ID 10
    ok 3 - Thread: Object ID 10

           Thread: Object ID 2
    ok 4 - Thread: Object ID 2

    BUG!   Main: Object ID 10 (should be 2)
    ok 5 - Main: Object ID 2
           Main: Object ID 2
    1..5

As you can see, after the thread ends, $$obj has the value
from the original object.  Then in the is() call, $$obj
becomes the 'correct' value.

I thought maybe Test::More might be a factor, but commenting
out all the is() calls doesn't fix $$obj after the thread exits.
Further, replacing the final is() call with a dummy() no-op
call does the same thing - it reverts $$obj to the correct
value.

Thanks.

Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About