On Monday, 15 October 2018 at 23:30:43 UTC, Stanislav Blinov
wrote:
On Monday, 15 October 2018 at 21:51:43 UTC, Manu wrote:
If a shared method is incompatible with an unshared method,
your class is broken.
What?!? So... my unshared methods should also perform all
that's necessary for `shared` methods?
No, its the other way around: a shared method that does extra
synchronisation should work irrespective of wether or not the
object needs that synchronisation. e.g. atomic loading a TLS
variable is fine.
Explicit casting doesn't magically implement thread-safety, it
basically just guarantees failure.
It doesn't indeed. It does, however, at least help prevent
silent bugs. Via that same guaranteed failure. That failure is
about all the help we can get from the compiler anyway.
What I suggest are rules that lead to proper behaviour with
respect to writing a thread-safe API.
You can write bad code with any feature in any number of ways.
Yup. For example, passing an int* to a function expecting
shared int*.
That is a reasonable thing to do if shared is const + no
unsynched reads.
I see it this way:
If your object has shared methods, then it is distinctly and
*deliberately* involved in thread-safety. You have deliberately
opted-in to writing a thread-safe object, and you must deliver
on your promise.
The un-shared API of an object that supports `shared` are not
exempt from the thread-safety commitment, they are simply the
subset of the API that may not be called from a shared context.
And therefore they lack any synchronization. So I don't see how
they *can* be "compatible" with `shared` methods.
I think Manu means you have a shared object with some shared
methods and some unshared methods. The shared methods deal with
synchronisation and can therefore be call from anywhere by
anyone, whereas the unshared methods must be called on a locked
object.
snip
Nobody writes methods of an object such that they don't work
with each other... methods are part of a deliberately crafted
and packaged
entity. If you write a shared object, you do so deliberately,
and you buy responsibility of making sure your objects API is
thread-safe.
If your object is not thread-safe, don't write shared methods.
Ahem... Okay...
import std.concurrency;
import core.atomic;
void thread(shared int* x) {
(*x).atomicOp!"+="(1);
}
shared int c;
void main() {
int x;
auto tid = spawn(&thread, &x); // "just" a typo
}
You're saying that's ok, it should "just" compile. It
shouldn't. It should produce an error and a mild electric
discharge into the developer's chair.
Indeed that is just a typo, just as that is a contrived example.
You'd notice that pretty quick in a debugger.