October 23, 2018 Re: shared - i need it to be useful | ||||
---|---|---|---|---|
| ||||
Posted in reply to John Colvin | On Monday, 22 October 2018 at 21:40:23 UTC, John Colvin wrote:
> On Monday, 15 October 2018 at 18:46:45 UTC, Manu wrote:
>> Okay, so I've been thinking on this for a while... I think I have a pretty good feel for how shared is meant to be.
>>
>> [...]
>
> I don't understand how you can safely have simultaneously shared methods that can modify data and unshared references that can modify data.
>
> struct S {
> int* x;
> void incX() shared { ... }
> }
>
> auto x = new int;
> auto s = shared S(x);
>
> Now I have two references to x, one shared, one unshared, both can be written to.
>
> What am I missing?
S's constructor is not written in such a way as to disallow unsafe, mutable sharing of S.x. S.x is not private, and there's no indication that any attempt has been made to block off other avenues of access to S.x (other code in the same module could access it). S.incX is not @safe.
I don't know for sure what's inside S.incX, but let's assume it's this:
void incX() shared {
atomicOp!"++"(x);
}
This will fail to compile under MP, since atomicOp would take a ref int, not a ref shared int as it does today (since no implicit conversion from shared to unshared is allowed).
To make it compile, you will need to explicitly cast it to unshared. Since incX is not @safe, you can do this without the compiler complaining. (this is why you should be writing all the code that you can, as @safe)
If we assume you perform no unsafe casts, then I have no idea what S.incX would be doing - int* can have no thread-safe, @trusted methods, so you can do absolutely nothing with S.x inside S's shared, @safe methods.
Most importantly though, why the hell are you trying to write such low-level code? The code you should be writing is this:
struct S {
Atomic!int x;
void incX() @safe shared {
x++;
}
}
Because Atomic!T has been written by an expert to be thread-safe.
This is why we've been repeating, over and over, again and again, that Joe Average Programmer should not be writing the foundational building blocks of MP.
--
Simen
|
October 23, 2018 Re: shared - i need it to be useful | ||||
---|---|---|---|---|
| ||||
Posted in reply to Simen Kjærås | On Tuesday, 23 October 2018 at 07:33:14 UTC, Simen Kjærås wrote:
> On Monday, 22 October 2018 at 21:40:23 UTC, John Colvin wrote:
>> [...]
>
> S's constructor is not written in such a way as to disallow unsafe, mutable sharing of S.x. S.x is not private, and there's no indication that any attempt has been made to block off other avenues of access to S.x (other code in the same module could access it). S.incX is not @safe.
>
> I don't know for sure what's inside S.incX, but let's assume it's this:
>
> void incX() shared {
> atomicOp!"++"(x);
> }
>
> This will fail to compile under MP, since atomicOp would take a ref int, not a ref shared int as it does today (since no implicit conversion from shared to unshared is allowed).
>
> To make it compile, you will need to explicitly cast it to unshared. Since incX is not @safe, you can do this without the compiler complaining. (this is why you should be writing all the code that you can, as @safe)
>
> If we assume you perform no unsafe casts, then I have no idea what S.incX would be doing - int* can have no thread-safe, @trusted methods, so you can do absolutely nothing with S.x inside S's shared, @safe methods.
>
> Most importantly though, why the hell are you trying to write such low-level code? The code you should be writing is this:
>
> struct S {
> Atomic!int x;
> void incX() @safe shared {
> x++;
> }
> }
>
> Because Atomic!T has been written by an expert to be thread-safe.
>
> This is why we've been repeating, over and over, again and again, that Joe Average Programmer should not be writing the foundational building blocks of MP.
>
> --
> Simen
I don't think this direction of me providing examples and you examining them is going to work, as I clearly don't (or at least I hope I don't currently) understand the proposal.
Is there an example something useful that would work and have an @safe API under this proposal? Something that includes the implicit cast from T* to shared(T)* and some shared methods?
|
October 23, 2018 Re: shared - i need it to be useful | ||||
---|---|---|---|---|
| ||||
Posted in reply to Neia Neutuladh | On Tuesday, 23 October 2018 at 01:26:57 UTC, Neia Neutuladh wrote:
> Somehow I lost track of your reason behind the promotion.
>
> Why not just ask to be able to call shared methods on a thread-local variable? No implicit casting; you need to take positive action to share anything. And if there's a non-shared overload, that's still preferred.
Because these have the same signature:
struct S {
void method() shared;
}
void func(ref shared S zis);
i.e. calling a shared method on a thread-local variable does require an implicit cast of the 'this' reference. Just like calling a 'const' method.
|
October 23, 2018 Re: shared - i need it to be useful | ||||
---|---|---|---|---|
| ||||
Posted in reply to Neia Neutuladh | On Tuesday, 23 October 2018 at 01:26:57 UTC, Neia Neutuladh wrote:
> On Mon, 15 Oct 2018 11:46:45 -0700, Manu wrote:
>>>From there, it opens up another critical opportunity; T* -> shared(T)*
>> promotion.
>> Const would be useless without T* -> const(T)* promotion. Shared suffers
>> a similar problem.
>> If you write a lock-free queue for instance, and all the methods are
>> `shared` (ie, threadsafe), then under the current rules, you can't
>> interact with the object when it's not shared, and that's fairly
>> useless.
>
> Somehow I lost track of your reason behind the promotion.
>
> Why not just ask to be able to call shared methods on a thread-local variable? No implicit casting; you need to take positive action to share anything. And if there's a non-shared overload, that's still preferred.
This is easily achievable with template this.
|
Copyright © 1999-2021 by the D Language Foundation