Shared

Jonathan M Davis newsgroup.d at jmdavisprog.com
Wed May 15 09:23:36 UTC 2019


On Wednesday, May 15, 2019 3:09:36 AM MDT Radu via Digitalmars-d wrote:
> On Wednesday, 15 May 2019 at 08:52:23 UTC, Jonathan M Davis wrote:
> > On Wednesday, May 15, 2019 1:56:12 AM MDT Radu via
> >
> > Digitalmars-d wrote:
> >> On Tuesday, 14 May 2019 at 21:02:10 UTC, Jonathan M Davis
> >>
> >> wrote:
> >> > On Tuesday, May 14, 2019 8:32:45 AM MDT Radu via
> >> > Digitalmars-d
> >> >
> >> > wrote:
> >> >> [...]
> >> >
> >> > Sure, it can guarantee that no reference will escape that
> >> > function, but all that's required is that another reference
> >> > to the same data exist elsewhere, and another thread could
> >> > muck with the object while the mutex was locked. There's no
> >> > question that helpers could be created which would help
> >> > users avoid mistakes when casting when casting away shared,
> >> > but the compiler can't actually make the guarantee that
> >> > casting away shared is thread-safe.
> >> >
> >> > - Jonathan M Davis
> >>
> >> My view is that the compiler could automatically insert
> >> locking logic (ala synchronized) when the shared parameters
> >> gets references inside the function, and also automatically
> >> cast away shared so for the function internals it would be
> >> like working with local non-shared data.
> >>
> >> Given that compiler inferes lifetime, it could safely elide
> >> locking if the parameter is passed to other functions that
> >> have the same signature (scope is explicit or inferred).
> >>
> >> The idea is to provide the tools that simplify concurrent
> >> programming, the compiler will need to insert all the checks
> >> automatically using the lifetime tracking.
> >
> > The compiler does not have enough information to know which
> > mutexes to use when even if we wanted it to insert locks. TDPL
> > synchronized classes are a special case in that they would
> > provide a way in the language to associate a specific lock with
> > a specific set of variables in a way that the compiler could
> > then guarantee that it's safe to remove the outer layer of
> > shared within a synchronized function. Without a similar
> > mechanism to associate a mutex with one or more variables and
> > guarantee that that mutex is always locked when they're
> > accessed, the compiler won't be able to even know what to lock,
> > let alone that it's safe to remove shared within a particular
> > section of code.
> >
> > And the issue with what you're proposing with scope is that
> > unless the compiler can actually guarantee that no other
> > references to the shared object exist which could be used to
> > access the object at the same time, then the compiler cannot
> > safely remove shared even temporarily. scope is just enough to
> > guarantee that that particular function can't escape any
> > references, not enough to guarantee that they don't exist. So,
> > while features like scope can be used to make it easier to
> > reason about the code and cast away shared in a way that your
> > code is thread-safe, I fully expect that it's going to have to
> > be up to the programmer to know when it's safe to remove
> > shared, thus requiring a cast or some other @trusted mechanism
> > to temporarily remove shared. TDPL synchronized classes are the
> > only proposal I've seen that would be able to guarantee
> > thread-safety, and it can only do it for what's directly in the
> > class, making TDPL synchronized classes arguably pretty useless
> > (on top of the fact that it means requiring classes when most D
> > code wouldn't normally use classes for something like this).
> >
> > - Jonathan M Davis
>
> Locks for classes can be done using the class monitor field (like
> synchronized works today). For other types the compiler could
> probably use the typeinfo class for locking, that might be to
> much for some cases. But there may be optimization opportunities,
> like for example use atomics when the target supports it and the
> type is a primitive, or assignment for the reference/pointer,
> same for binary ops when dereferencing a pointer to a primitive.
>
> scope role is to ensure lock/unlock semantics and to help ellide
> superfluous locking when chaining the calls. I'm not proposing a
> ownership system here.
> The shared castaway should be performed only inside the locked
> scope, the difference is that the compiler will automatically do
> that for you.
>
> I think this should be enabled only for @safe functions, and not
> for @system.

The problem is that unless the compiler can absolutely guarantee that no
other references to the data exist, having the compiler automatically
removing shared at all - including in @safe code - can't be safely done.
Without an ownership model, the compiler basically doesn't have the
information that it needs to know that such references don't exist. Just
because code is @safe doesn't mean that it's thread-safe, and scope does not
provide enough information for the compiler to know that it's thread-safe.
Ultimately, you need a programmer to examine the code to verify the
thread-safety - which arguably means that anything that removes shared needs
to be @system so that the programmer knows that they need to verify the
code.

- Jonathan M Davis





More information about the Digitalmars-d mailing list