shared - i need it to be useful

Stanislav Blinov stanislav.blinov at gmail.com
Thu Oct 18 19:01:20 UTC 2018


On Thursday, 18 October 2018 at 18:24:47 UTC, Manu wrote:

> I have demonstrated these usability considerations in 
> production. I am
> confident it's the right balance.

Then convince us. So far you haven't.

> I propose:
>  1. Normal people don't write thread-safety, a very small 
> number of
> unusual people do this. I feel very good about biasing 100% of 
> the
> cognitive load INSIDE the shared method. This means the expert, 
> and
> ONLY the expert, must make decisions about thread-safety 
> implementation.

No argument.

>  2. Implicit conversion allows users to safely interact with 
> safe
> things without doing unsafe casts. I think it's a complete 
> design fail
> if you expect any user anywhere to perform an unsafe cast to 
> call a
> perfectly thread-safe function. The user might not properly 
> understand
> their obligations.

Disagreed. "Normal" people wouldn't be doing any unsafe casts and 
*must not be able to* do something as unsafe as silent promotion 
of thread-local mutable data to shared. But it's perfectly fine 
for the "expert" user to do such a promotion, explicitly.

>  3. The practical result of the above is, any complexity 
> relating to
> safety is completely owned by the threadsafe author, and not 
> cascaded
> to the user. You can't expect users to understand, and make 
> correct
> decisions about threadsafety. Safety should be default position.

Exactly. And an implicit conversion from mutable to shared isn't 
safe at all.

> I recognise the potential loss of an unsafe optimised 
> thread-local path.
> 1. This truly isn't a big deal. If this is really hurting you, 
> you
> will notice on the profiler, and deploy a thread-exclusive path
> assuming the context supports it.

> 2. I will trade that for confidence in safe interaction every 
> day of
> the week. Safety is the right default position here.

Does not compute. Either you're an "expert" from above and live 
with that burden, or you're not.

> 2. You just need to make the unsafe thread-exclusive variant 
> explicit, eg:
>
>> struct ThreadSafe
>> {
>>     private int x;
>>     void unsafeIncrement() // <- make it explicit
>>     {
>>        ++x; // User has asserted that no sharing is possible, 
>> no reason to use atomics
>>     }
>>     void increment() shared
>>     {
>>        atomicIncrement(&x); // object may be shared
>>     }
>> }

No. The above code is not thread-safe at all. The private int 
*must* be declared shared. Then it becomes:

struct ThreadSafe {
     // These must be *required* if you want to assert any thread 
safety. Be nice
     // if the compiler did that for us.
     @disable this(this);
     @disable void opAssign(typeof(this));

     private shared int x; // <- *must* be shared

     void unsafeIncrement() @system {
         x.assumeUnshared += 1;
     }

     // or deduced:

     void unsafeIncrement()() // assumeUnshared must be @system, 
thus this unsafeIncrement will also be deduced @system
     {
         x.assumeUnshared += 1;
     }

     void increment() shared {
         x.atomicOp!"+="(1);
     }
}

> I think this is quiet a reasonable and clearly documented 
> compromise.

With the fixes above, it is. Without them, it will only be 
apparent from documentation, and who writes, or reads, that?..

> I think absolutely-reliably-threadsafe-by-default is the right 
> default position.

But it is exactly the opposite of automatic promotions from 
mutable to shared!


More information about the Digitalmars-d mailing list