An Issue I Wish To Raise Awareness On

Jonathan M Davis via Digitalmars-d digitalmars-d at puremagic.com
Fri Jul 21 15:02:41 PDT 2017


On Friday, July 21, 2017 08:37:51 Atila Neves via Digitalmars-d wrote:
> On Thursday, 20 July 2017 at 21:20:46 UTC, Jonathan M Davis wrote:
> > On Thursday, July 20, 2017 07:40:35 Dominikus Dittes Scherkl
> >
> > via Digitalmars-d wrote:
> >> On Wednesday, 19 July 2017 at 22:35:43 UTC, Jonathan M Davis
> >>
> >> wrote:
> >> > The issue isn't the object being destroyed. It's what it
> >> > refers to via its member variables. For instance, what if an
> >> > object were to remove itself from a shared list when it's
> >> > destroyed (e.g. because it's an observer in the observer
> >> > pattern). The object has a reference to the list, but it
> >> > doesn't own it.
> >>
> >> So, even a thread-local object that has references to a shared
> >> list
> >> has to handle those as shared, even in its non-shared
> >> destructor.
> >> I can't follow your argument.
> >
> > You can't just strip off shared. To do so defeats the purpose
> > of shared. If you have something like
> >
> > struct S
> > {
> >
> >      shared List<Foo> _list;
> >
> >      ~this()
> >      {
> >
> >         ...
> >
> >      }
> >
> > }

Wow. I've been doing too much C++ lately apparently, since I used <>. :|

> This is fine. What dmd does now is strip shared off of the `this`
> pointer, not the member variables. There's only a problem if the
> sharedness of the member variable(s) depends on sharedness of the
> enclosing object.

What happens with something like

struct S
{
    Foo* _foo;

    ~this() {...}
}

shared S s;

Inside the destructor, is what _foo points to still treated as shared:
shared(Foo)*? i.e. is the outer layer of shared the only layer being made
thread-local - like what would supposedly happen with synchronized classes?
If so, then that largely solves the problem. The only issue is pointers to
the member variables, which would not be @safe but would still technically
be possible, in which case something outside the struct could still
reference the member variables from another thread. But given that that's
going to blow up in your face soon thereafter anyway, since the object is
being destroyed (and thus you screwed up making sure that your @system code
was @safe), that's probably fine.

However, if _foo is treated as Foo* instead of shared(Foo)* in the
destructor, then there definitely is a problem. The fact that when the
member variable is explicitly shared, it continues to be treated as shared
definitely reduces the problem, but it doesn't fully close the hole. The
parts of the member variables not directly in the object still need to be
treated as shared, because they aren't necessarily owned or controlled by
the object and could legally and @safely be manipulated from other threads
even while the destructor is running. So, are they still treated as shared,
or are they treated as fully thread-local? I would have thought that they'd
still be treated as thread-local given that the shared part is then only
known to the variable that was marked as shared and not the destructor
itself, since it's the same destructor for thread-local and shared objects.

And if the destructor treats the member variables as completely thread-local
(rather than just the outer layer as thread local) even when the object
itself was shared, then I don't think that this is a viable solution. It
would either need to be made illegal to make an object shared if it has
indirections and a destructor, or it needs to have a shared destructor.

- Jonathan M Davis



More information about the Digitalmars-d mailing list