June 22, 2019
On Sat., 22 Jun. 2019, 9:40 am Walter Bright via Digitalmars-d, < digitalmars-d@puremagic.com> wrote:

> On 6/21/2019 5:07 AM, Manu wrote:
> > There is no "between threads" unless you have already entered @trusted
> land.
> > The reason for my proposal in the OP is precisely to prevent passing data to other threads, that's the key that makes this promotion safe.
>
> Scope doesn't do that. I keep saying this. But the premise is strange,
> anyway,
> as why would you want to convert a reference to shared if not to bass it
> to
> another thread?
>

Because it's safe to do from the calling scope's perspective, and that's the needed entry vector into a @trusted solution.

It is also useful too in some cases to reduce needlessly overloading methods which have a threadsafe implementation.

> Can you show how you managed to get a ref to another thread without
> > entering @trusted?
> There's no such thing as a ref to another thread. You can pass a ref to
> another
> thread in a scope function, as long as the ref doesn't survive the scope
> of foo().
>
> The compiler cannot check that, though, and so cannot bless the implicit conversion to shared. I've said this 4 or 5 times now.
>

Compiler is not required to check the users work in @trusted code. It assumes the user conformed with language requirements.


June 21, 2019

1. `scope` requires that the reference to `x` passed to fun() does not persist past the return of fun(). If fun() is @trusted, fun() can do anything it likes, including passing the reference to other threads, as long as fun() does some sort of synchronization to ensure the other threads no longer hold that reference past the return of fun().

2. `scope` does not require memory cache coherency happen upon exit from fun(). Therefore, a non-atomic read of `x` after fun() exits is not guaranteed to have the latest value of `x`.

---

A corollary:

1. D has no `@safe` mechanism to convert shared references back to thread local. In particular, `scope` isn't it.
June 22, 2019
On Saturday, 22 June 2019 at 03:03:38 UTC, Walter Bright wrote:
> 1. `scope` requires that the reference to `x` passed to fun() does not persist past the return of fun(). If fun() is @trusted, fun() can do anything it likes, including passing the reference to other threads, as long as fun() does some sort of synchronization to ensure the other threads no longer hold that reference past the return of fun().
>
> 2. `scope` does not require memory cache coherency happen upon exit from fun(). Therefore, a non-atomic read of `x` after fun() exits is not guaranteed to have the latest value of `x`.

So you basically say that you need "x" to be typed as const when calling fun() if fun() transfers "x" to another thread.


Ola
June 22, 2019
On 6/21/2019 5:26 PM, Manu wrote:
> I've asked you 5 or 6 times to show how to pass a pointer to another thread without violating scope.
> Can you show it? You keep saying you can.

    void foo(scope shared(int)* p) @trusted {
        auto t = startThread();
        passToThread(t, p);
        waitForThreadToExit(t);
    }


> You need an acquire fence before the function returns, it's trivial.

That's right it is. But the compiler doesn't know you put one there, and scope does not cause it to be put there, and @safe does not, either.


> If you want @safe expansion, that's future work, and I personally couldn't care less about that work. I can create safe libraries with @trusted functions, and I could do it _right now_.

You're assuming semantics for scope and @safe that are not there, and so the compiler cannot assume them, either.

June 22, 2019
On 6/21/2019 5:33 PM, Manu wrote:
> Because it's safe to do from the calling scope's perspective,

No, it is not.


> Compiler is not required to check the users work in @trusted code. It assumes the user conformed with language requirements.

The language does not require you to put the fence in, hence it cannot assume you did.

I don't know how else to explain it to you. Your example does not work.
June 22, 2019
On Sat, Jun 22, 2019 at 5:57 PM Walter Bright via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>
> On 6/21/2019 5:26 PM, Manu wrote:
> > I've asked you 5 or 6 times to show how to pass a pointer to another thread
> > without violating scope.
> > Can you show it? You keep saying you can.
>
>      void foo(scope shared(int)* p) @trusted {
>          auto t = startThread();
>          passToThread(t, p);
>          waitForThreadToExit(t);
>      }

I don't believe `passToThread` could receive a `scope shared(int)*`... can you show an implementation of passToThread?

> > You need an acquire fence before the function returns, it's trivial.
>
> That's right it is. But the compiler doesn't know you put one there, and scope does not cause it to be put there, and @safe does not, either.

There couldn't have been cross-thread communication if it was @safe.

> > If you want @safe expansion, that's future work, and I personally couldn't care less about that work. I can create safe libraries with @trusted functions, and I could do it _right now_.
>
> You're assuming semantics for scope and @safe that are not there, and so the compiler cannot assume them, either.

The compiler can assume that you didn't pass a scope value to another
thread, because it would be impossible to do.
Show how to do it? Your example above shows passToThread, but I'm just
going to ask you to show how that function works, and we'll recurse
until either the value reaches another thread, or you agree that scope
prevents a value from escaping...
June 22, 2019
On Sat, Jun 22, 2019 at 6:00 PM Walter Bright via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>
> On 6/21/2019 5:33 PM, Manu wrote:
> > Because it's safe to do from the calling scope's perspective,
>
> No, it is not.
>
>
> > Compiler is not required to check the users work in @trusted code. It assumes the user conformed with language requirements.
>
> The language does not require you to put the fence in, hence it cannot assume you did.
>
> I don't know how else to explain it to you. Your example does not work.

Your code snippet is incomplete; show the implementation of passToThread()...
June 22, 2019
On Saturday, 22 June 2019 at 07:53:49 UTC, Walter Bright wrote:
> On 6/21/2019 5:26 PM, Manu wrote:
>> You need an acquire fence before the function returns, it's trivial.
>
> That's right it is. But the compiler doesn't know you put one there, and scope does not cause it to be put there, and @safe does not, either.


I think perhaps it would be more clear if you make a distinction between:


1. fences that inform the compiler that "virtual registers" could be stale (conceptual entities at compile time)

2. fences targeting cache coherency (that hardware caches are stale at runtime).


If fun() is separately compiled then there should be no distinction. The calling context must assume that fun() might have changed the values.

So it does not affect (1). And if fun() flushes the caches explicitly or explictly loads the values changed by other threads after they are done, then it should not affect (2) either.

Right?


Ola.

June 22, 2019
On 6/22/2019 1:03 AM, Manu wrote:
> Your code snippet is incomplete; show the implementation of passToThread()...

Doesn't make any difference.

June 22, 2019
On 6/22/2019 1:02 AM, Manu wrote:
> I don't believe `passToThread` could receive a `scope shared(int)*`...
> can you show an implementation of passToThread?

In @system code you can do whatever you like.