Title here
Summary here
In the previous example we saw how to manage simple counter state using atomic operations. For more complex state we can use a mutex to safely access data across multiple threads.
import std.stdio;
import core.sync.mutex;
import std.concurrency;
// Container holds a map of counters; since we want to
// update it concurrently from multiple threads, we
// add a Mutex to synchronize access.
// Note that mutexes must not be copied, so if this
// struct is passed around, it should be done by
// pointer.
class Container {
private Mutex mu;
private int[string] counters;
this() {
mu = new Mutex();
counters = ["a": 0, "b": 0];
}
// Lock the mutex before accessing counters; unlock
// it at the end of the function using a scope(exit) statement.
void inc(string name) {
synchronized(mu) {
counters[name]++;
}
}
}
void main() {
auto c = new Container();
// This function increments a named counter
// in a loop.
void doIncrement(string name, int n) {
for (int i = 0; i < n; i++) {
c.inc(name);
}
}
// Run several threads concurrently; note
// that they all access the same Container,
// and two of them access the same counter.
auto t1 = spawn(&doIncrement, "a", 10000);
auto t2 = spawn(&doIncrement, "a", 10000);
auto t3 = spawn(&doIncrement, "b", 10000);
// Wait for the threads to finish
thread_joinAll();
writeln(c.counters);
}
Running the program shows that the counters updated as expected.
$ dmd -run mutexes.d
["a": 20000, "b": 10000]
Next we’ll look at implementing this same state management task using only threads and message passing.
In this D version:
core.sync.mutex.Mutex
for mutual exclusion.std.concurrency
module to spawn threads.Container
is implemented as a class instead of a struct.synchronized(mu)
instead of explicitly calling Lock()
and Unlock()
.WaitGroup
, so we use thread_joinAll()
to wait for all threads to complete.doIncrement
function is defined inside main()
to have access to the Container
instance.This example demonstrates how to use mutexes in D to safely access shared data from multiple threads, achieving the same functionality as the original code.