On 10/15/2018 11:46 AM, Manu wrote:
[...]

Shared has one incredibly valuable feature - it allows you, the programmer, to identify data that can be accessed by multiple threads. There are so many ways that data can be shared, the only way to comprehend what is going on is to build a wall around shared data.

(The exception to this is immutable data. Immutable data does not need synchronization, so there is no need to distinguish between shared and unshared immutable data.)

This falls completely apart if shared and unshared data can be aliased. When Andrei and I came up with the rules for:

   mutable
   const
   shared
   const shared
   immutable

and which can be implicitly converted to what, so far nobody has found a fault in those rules. Timon Gehr has done a good job showing that they still stand unbreached.

So, how can mutable data become shared, and vice versa? I've never found a way to do that that is proveably safe. Therefore, it's up to the programmer.

If a programmer does the following:

    T* p;
    shared(T)* sp;

    p = cast(T*)sp;           (1)
    sp = cast(shared(T)*) p;  (2)

those casts will be rejected in @safe code. They'll have to be in @trusted or @system code. It will be up to the programmer to ensure (via mutexes, locks, uniqueness, etc.) that:

(1) sp is a unique pointer and that ownership of the data is thus transferred for the lifetime of p

(2) p is a unique pointer and that ownership of the data is thus transferred for the lifetime of sp

A sensible program should try to minimize the places where there are these "gates" through the wall, as those gates will be where you'll be looking when threading bugs appear.

Allowing implicit aliasing between shared and unshared data means the entire program needs to reviewed for threading bugs, rather than just the shared parts. One might as well just not have shared as a language feature at all. D being a systems programming language, one can certainly write code that way, just like one does with C, and with all of the threading bugs one gets doing that.

----------

Currently, the compiler allows you to read/write shared data without any locks or atomics. I.e. the compiler doesn't attempt to insert any synchronization on your behalf. Given all the ways synchronization can be done, it just seems presumptive and restrictive to impose a particular scheme. It's pretty much left up to the user.

Which is why I recommend minimizing the amount of code that actually has to deal with shared data.

Reply via email to