On 10/18/18 10:11 AM, Simen Kjærås wrote:
On Thursday, 18 October 2018 at 13:35:22 UTC, Steven Schveighoffer wrote:
struct ThreadSafe
{
private int x;
void increment()
{
++x; // I know this is not shared, so no reason to use atomics
}
void increment() shared
{
atomicIncrement(&x); // use atomics, to avoid races
}
}
But this isn't thread-safe, for the exact reasons described elsewhere in
this thread (and in fact, incorrectly leveled at Manu's proposal).
Someone could write this code:
void foo() {
ThreadSafe* a = new ThreadSafe();
shareAllOver(a);
Error: cannot call function shareAllOver(shared(ThreadSafe) *) with type
ThreadSafe *
a.increment(); // unsafe, non-shared method call
}
When a.increment() is being called, you have no idea if anyone else is
using the shared interface.
I do, because unless you have cast the type to shared, I'm certain there
is only thread-local aliasing to it.
This is one of the issues that MP (Manu's Proposal) tries to deal with.
Under MP, your code would *not* be considered thread-safe, because the
non-shared portion may interfere with the shared portion. You'd need to
write two types:
struct ThreadSafe {
private int x;
void increment() shared {
atomicIncrement(&x);
}
}
struct NotThreadSafe {
private int x;
void increment() {
++x;
}
}
These two are different types with different semantics, and forcing them
both into the same struct is an abomination.
Why? What if I wanted to have an object that is local for a while, but
then I want it to be shared (and I ensure carefully when I cast to
shared that there are no other aliases to that)?
In your case, the user of your type will need to ensure thread-safety.
No, the contract the type provides is: if you DON'T cast unshared to
shared or vice versa, the type is thread-safe.
If you DO cast unshared to shared, then the type is thread-safe as long
as you no longer use the unshared reference.
This is EXACTLY how immutable works.
You may not have any control over how he's doing things, while you *do*
control the code in your own type (and module, since that also affects
things). Under MP, the type is what needs to be thread-safe, and once it
is, the chance of a user mucking things up is much lower.
Under MP, the type is DEFENSIVELY thread-safe, locking or using atomics
unnecessarily when it's thread-local.
-Steve