September 13, 2018
Class core.sync.Mutex has shared and non-shared versions of its methods. This is logical — mutex is shared between threads. But class core.sync.Condition doesn't have shared methods at all. Why? Maybe I missed something, but it's very strange for me, because such code doesn't work:
---class Foo {    private Mutex mtx;    private Condition cnd;
    shared this() {        mtx = new Mutex(this); // error: no constructor
Mutex(shared Object)        cnd = new Condition(mtx); // error: no
constructor Condition(shared Mutex)    }}---
Please enlighten me)


September 13, 2018
On Thursday, September 13, 2018 5:00:31 AM MDT Michael Galuza via phobos wrote:
> Class core.sync.Mutex has shared and non-shared versions of its methods.
> This is logical — mutex is shared between threads. But class
> core.sync.Condition doesn't have shared methods at all. Why? Maybe I
> missed something, but it's very strange for me, because such code doesn't
> work: ---class Foo {    private Mutex mtx;    private Condition cnd;
>     shared this() {        mtx = new Mutex(this); // error: no constructor
> Mutex(shared Object)        cnd = new Condition(mtx); // error: no
> constructor Condition(shared Mutex)    }}---
> Please enlighten me)

It's likely because they predate shared, and when shared was added, the main person maintaining that code was very leery of adding shared to anything until shared was better sorted out. shared has since been added to some of that stuff, but it hasn't been added consistently. I'd have to look them over in detail to say for sure which should and should be shared, but probably pretty much all of the methods on Mutex and Condition should be shared. Mutex probably has both shared and non-shared in order to avoid breaking code, and Condition has probably simply never been updated. Because we have synchronized and std.concurrency in the language, Mutex and Conditional don't need to be used directly anywhere near as much as they would be with most languages, and even though it's a terrible idea, many folks have tended to use __gshared instead of shared, because then the compiler won't scream at them about trying to do something with shared (which then risks serious bugs, because the compiler assumes that anything that isn't shared is thread-local).

In general, shared objects shouldn't be able to do much of anything unless they're protected by a mutex and have shared temporarily cast away, but mutexes and conditional variables are one of the few instances where it does make sense to have a shared object that actually has stuff called on it as shared. The big problem overall though is that while the basics of shared were figured out years ago, the details were never completed (e.g. copying shared objects is not thread-safe, so it shouldn't be legal, but it is, and some of the runtime and standard library stuff isn't set up properly to use shared - as if you've found here). Walter and Andrei intend to finish designing the fine details of shared, but it hasn't gotten high enough up on the priority list yet to have actually happened yet. And because that hasn't happened yet, shared hasn't gotten enough of a focus as it should have for stuff like ensuring that the stuff in druntime is marked with shared appropriately.

And avoiding code breakage when code has actually been updated has been a bit entertaining - e.g. IIRC, most of the functions on Mutex really should be nothrow, but because Mutex is a class and folks can derive from it, adding nothrow would break existing code, and vibe.d had derived from it to do something. So, while this stuff does need to get sorted out, it's not always easy to do cleanly.

- Jonathan M Davis




_______________________________________________
phobos mailing list
phobos@puremagic.com
http://lists.puremagic.com/mailman/listinfo/phobos