Synchronization & Sharing

Although the preferred way in D to do multi-threading is to rely on immutable data and synchronize threads using message passing, the language has built-in support for synchronization primitives as well as type system support with shared to mark objects that are accessed from multiple threads.

The shared type identifier allows to mark variables that are shared among different threads:

shared(int)* p = new int;
int* t = p; // ERROR

For example std.concurrency.send just allows to send either immutable or shared data and copying the message to be sent. shared is transitive so if a class or struct is marked shared all its members will be too. Note that static variables aren't shared by default because they are implemented using thread local storage (TLS) and each thread gets its own variable.

synchronized blocks allow to instruct the compiler to create a critical section that can only be entered by one thread at a time.

synchronized {
    importStuff();
}

Within class member functions these blocks might be limited to different member objects mutexes with synchronized(member1, member2) to reduce contention. The D compiler inserts critical sections automatically. A whole class can be marked as synchronized as well and the compiler will make sure that just one thread accesses a concrete instance of it at a time.

Atomic operations on shared variables can be performed using the core.atomic.atomicOp helper:

shared int test = 5;
test.atomicOp!"+="(4);

In-depth

rdmd playground.d

{{programOutput}}