Skip to content
Concurrency
step 1/5

Reading — step 1 of 5

Learn

~2 min readConcurrency, Mixins, C Interop

D has multiple concurrency models. The recommended one is message-passing via std.concurrency.

Message passing

import std.stdio;
import std.concurrency;

void worker() {
    // Receive a message from the spawning thread
    auto msg = receiveOnly!string();
    writeln("got: ", msg);
}

void main() {
    auto tid = spawn(&worker);
    send(tid, "hello");
    thisTid;    // current thread's Tid
}
  • spawn(&fn, args...) — start a thread. Args copied (must be shared or value types).
  • send(tid, msg) — async send.
  • receiveOnly!T() — block, receive exactly type T.
  • receive((int x) { }, (string s) { }) — pattern-match on type.

Shared state via shared

D's type system distinguishes thread-local from shared:

int x = 5;             // thread-local — each thread has own copy
shared int counter = 0; // explicitly shared across threads

Most variables are thread-local by default — surprising for C/C++ programmers, but eliminates a huge class of bugs.

Atomics

import core.atomic;
shared int counter = 0;
void inc() {
    counter.atomicOp!"+="(1);
}

Synchronized classes

synchronized class Counter {
    private int count = 0;
    void inc() { count++; }
    int get() { return count; }
}

Methods on a synchronized class hold the object's monitor — like Java's synchronized.

Fibers

Lightweight cooperative threading:

import core.thread;

void worker() {
    Fiber.yield;
    writeln("resumed");
}

auto f = new Fiber(&worker);
f.call;            // runs to first yield
f.call;            // resumes

Fibers are stackful coroutines. Used for async I/O frameworks (vibe.d).

std.parallelism

For parallel algorithms:

import std.parallelism;

int[] data = [1, 2, 3, 4, 5, 6, 7, 8];
auto sum = data.taskPool.reduce!"a + b"(0);

foreach (i; parallel(iota(0, 1000))) {
    process(i);
}

Parallelizes the foreach across CPU cores. Each iteration runs on a worker thread.

When to use which

  • Message passing — most apps, isolation is good
  • shared + atomics — high-performance counters, lock-free DS
  • Synchronized — traditional OOP
  • Fibers — async I/O, streaming
  • std.parallelism — embarrassingly parallel data processing

D's type system pushes you toward the right tool. Thread-local-by-default is the unique D innovation here.

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…