|Posted by Petar Kirov [ZombineDev]|
in reply to Arun Chandrasekaran
Posted in reply to Arun Chandrasekaran
On Thursday, 14 December 2017 at 07:04:49 UTC, Arun Chandrasekaran wrote:
> What are the reasoning behind core.sync.* primitives being classes and not structs?
There are several reasons as far as I know:
1) Structs in D can't have non-trivial constructors - i.e. you can't call pthread_mutex_init or InitializeCriticalSection to initialize the underlying OS object. If you go with structs, every call to lock, tryLock and unlock would have to first check if the object has been initialized, and the code would have to guard the initialization from data races. Or alternatively, the code would be unsafe, just like the pthread_* and Win32 APIs.
2) Structs in D best model values, something that doesn't have an identity and could be freely copied around. Yes, you can disable post-blit (with @disable `this(this);`) and opAssign, but given the fact that any API that uses them will receive the sync object by reference (e.g. either `Mutex*` or `ref Mutex`) if they were implemented as structs, it would really look better on the API level to simply have reference types.
3) Polymorphism. Third-party libraries like vibe-d have custom synchronization primitives that inherit those in druntime and override their functionality, in vibe-d's case to make them compatible with Fibers.
4) Class monitors currently work through the object.Object.Monitor interface, which core.sync.mutex.Mutex implements.
> This prevents them from being placing on shared memory.
Do you mean shared in the OS sense (mmap with MAP_ANONYMOUS | MAP_SHARED and whatever the Win32 analog is), or in the sense of the D type qualifier, e.g. shared(Mutex)?
If you mean shared(Mutex), that should already work since I fixed it a couple of releases ago. I haven't yet had the time to do the work for the rest of core.sync.*, though.
If you mean process shared memory, I agree that there are many valid cases where you want to be in control of the memory. I have been thinking about extracting the core of the synchronization primitives into @system structs, so users can have more control over them, though I haven't had the time for that either.
For now you have two options:
A) roll your own struct-based implementations
B) manually emplace the class instances on your piece of void memory. See https://github.com/dlang/druntime/blob/v2.077.1/src/core/sync/mutex.d#L342 for an example.