Synchronization & Sharing

In D, the preferred way to do multi-threading is to rely on immutable data and synchronize threads using message passing. However, 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.

Use the shared type identifier to mark variables that are shared among different threads:

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

For example std.concurrency.send only allows sending 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 are used to tell 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 in which case 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