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);