`shared`...

Manu turkeyman at gmail.com
Mon Oct 1 23:09:21 UTC 2018


On Mon, Oct 1, 2018 at 8:55 AM Timon Gehr via Digitalmars-d
<digitalmars-d at puremagic.com> wrote:
>
> On 01.10.2018 04:29, Manu wrote:
> > struct Bob
> > {
> >    void setThing() shared;
> > }
> >
> > As I understand, `shared` attribution intends to guarantee that I dun
> > synchronisation internally.
> > This method is declared shared, so if I have shared instances, I can
> > call it... because it must handle thread-safety internally.
> >
> > void f(ref shared Bob a, ref Bob b)
> > {
> >    a.setThing(); // I have a shared object, can call shared method
> >
> >    b.setThing(); // ERROR
> > }
> >
> > This is the bit of the design that doesn't make sense to me...
> > The method is shared, which suggests that it must handle
> > thread-safety. My instance `b` is NOT shared, that is, it is
> > thread-local.
> > So, I know that there's not a bunch of threads banging on this
> > object... but the shared method should still work! A method that
> > handles thread-safety doesn't suddenly not work when it's only
> > accessed from a single thread.
> > ...
>
> shared on a method does not mean "this function handles thread-safety".
> It means "the `this` pointer of this function is not guaranteed to be
> thread-local". You can't implicitly create an alias of a reference that
> is supposed to be thread-local such that the resulting reference can be
> freely shared among threads.

I don't understand. That's the point of `scope`... is that it won't
escape the reference. 'freely shared' is the antithesis of `scope`.

> > I feel like I don't understand the design...
> > mutable -> shared should work the same as mutable -> const... because
> > surely that's safe?
>
> No. The main point of shared (and the main thing you need to understand)
> is that it guarantees that if something is _not_ `shared` is is not
> shared among threads. Your analogy is not correct, going from
> thread-local to shared is like going from mutable to immutable.

We're talking about `mutable` -> `shared scope`. That's like going
from mutable to const.
`shared scope` doesn't say "I can share this", what it says is "this
may be shared, but *I won't share it*", and that's the key.
By passing a thread-local as `shared scope`, the receiver accepts that
the argument _may_ be shared (it's not in this case), but it will not
become shared in the call. That's the point of scope, no?

> If the suggested typing rule was implemented, we would have the
> following way to break the type system, allowing arbitrary aliasing
> between mutable and shared references, completely defeating `shared`:
>
> class C{ /*...*/ }
>
> shared(C) sharedGlobal;
> struct Bob{
>      C unshared;
>      void setThing() shared{
>          sharedGlobal=unshared;
>      }
> }
>
> void main(){
>      C c = new C(); // unshared!
>      Bob(c).setThing();
>      shared(D) d = sharedGlobal; // shared!
>      assert(c !is d); // would fail (currently does not even compile)
>      // sendToOtherThread(d);
>      // c.someMethod(); // (potential) race condition on unshared data
> }

Your entire example depends on escaping references. I think you missed
the point?


More information about the Digitalmars-d mailing list