Concurrency

37.1 Thread-Local by Default

Globals and statics are thread-local. Sharing requires shared, immutable, or __gshared. This prevents accidental data races.

37.2 Message Passing (std.concurrency)

Only immutable, shared, or value types (without mutable indirections) can be sent. This is enforced by the compiler.

spawnLinked, register/locate (named threads), setMaxMailboxSize, prioritySend.

import std.concurrency, std.stdio;

void worker()
{
    bool running = true;
    while (running)
    {
        receive(
            (int n) { ownerTid.send(n * n); },
            (string cmd) { if (cmd == "stop") running = false; },
            (OwnerTerminated e) { running = false; }
        );
    }
}

void main()
{
    auto tid = spawn(&worker);
    foreach (i; 1 .. 4)
    {
        tid.send(i);
        writeln(receiveOnly!int);
    }
    tid.send("stop");
    auto got = receiveTimeout(100.msecs, (int x) {});   // with a timeout
}

37.3 Threads (core.thread)

import core.thread;
auto t = new Thread({ writeln("in thread"); });
t.start();
t.join();
Thread.sleep(dur!"msecs"(100));
auto group = new ThreadGroup;
foreach (i; 0 .. 4) group.create({ /* work */ });
group.joinAll();

37.4 shared, Synchronization and Atomics

Casting away shared inside a lock is the common (@trusted) pattern. -preview=nosharedaccess forbids direct access to shared data without atomics or casts.

import core.atomic, core.sync.mutex, core.sync.condition;

shared int counter;
void incr() { atomicOp!"+="(counter, 1); }
int v = atomicLoad(counter);
atomicStore(counter, 0);
cas(&counter, 0, 1);                             // compare-and-swap

class SafeCounter
{
    private int count;
    synchronized void increment() { count++; }   // a synchronized class/method locks the monitor
    synchronized int get() { return count; }
}

__gshared Mutex mtx;
shared static this() { mtx = new Mutex; }
void critical() { mtx.lock(); scope(exit) mtx.unlock(); /* ... */ }
synchronized (mtx) { /* block-level lock */ }
// Also: ReadWriteMutex, Condition, Semaphore, Barrier, core.sync.event