While messing with atomicLoad [1], I noticed that dmd lets me implicitly convert values to/from shared without restrictions. It's in the spec [2]. This seems bad to me.

Here's how I understand shared. If anything's wrong, I'd appreciate if someone would educate me.

Shared is there to prevent me from accidentally writing code that's not thread-safe (at a low level).

When I never use shared (or __gshared or other mean hacks), I only ever get thread-local variables and I can't share data between threads. I get thread safety by avoiding the issue entirely.

When I do use shared, the compiler is supposed to reject (low-level) operations that are not thread-safe. That's why ++x is deprecated for a shared x, and I'm told to use atomicOp!"+=" instead.

Of course I can still do a verbose unsafe version which the compiler can't catch:

    atomicStore(x, atomicLoad(x) + 1);

The compiler can't possibly know which high-level operations need to run uninterrupted, so there's nothing it can do about this.

Back to implicit conversions. Loading and storing is as low-level as it gets. When D disallows unsafe ++ on shared, surely it should also disallow unsafe loading and storing.

Copying a shared value type to an unshared one could be defined as doing an atomic load, and copying the other way around could result in an atomic store. I don't think it's specified or implemented like this at the moment, but it would make sense to me. Loading/storing overly large value types can probably not be made thread-safe like that.

So, conclusion/proposal:

* Conversion of a value type from shared to unshared should only be allowed if it can be done with an atomic load. The compiler should generate the atomic load. * Conversion of a value type from unshared to shared should only be allowed if it can be done with an atomic store. The compiler should generate the atomic store.
* Other conversions are not allowed.

Or alternatively, simply disallow all those conversions, and tell the user that they have to ensure thread safety themselves, e.g. by using atomicLoad/atomicStore.

Sorry for the noise if this is all known and part of the "shared isn't implemented" mantra. I couldn't find a bugzilla issue.


[1] https://github.com/dlang/druntime/pull/1605
[2] https://dlang.org/spec/const3.html#implicit_conversions (first sentence)

Reply via email to