import std.threading;
// 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
// class is passed around, it should be done by
// reference.
class Container {
private Mutex@ mu;
private dictionary counters;
Container() {
@mu = Mutex();
counters = dictionary();
}
// Lock the mutex before accessing counters; unlock
// it at the end of the function.
void inc(const string &in name) {
mu.lock();
if (counters.exists(name))
int(counters[name]) += 1;
else
counters[name] = 1;
mu.unlock();
}
}
void main() {
Container container;
container.counters["a"] = 0;
container.counters["b"] = 0;
array<Thread@> threads;
// This function increments a named counter
// in a loop.
void doIncrement(Container@ c, const string &in 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.
threads.insertLast(Thread(function(Container@ c) { doIncrement(c, "a", 10000); }, @container));
threads.insertLast(Thread(function(Container@ c) { doIncrement(c, "a", 10000); }, @container));
threads.insertLast(Thread(function(Container@ c) { doIncrement(c, "b", 10000); }, @container));
// Wait for the threads to finish
for (uint i = 0; i < threads.length(); i++) {
threads[i].join();
}
print("Counters: " + container.counters.getKeys()[0] + "=" + int(container.counters[container.counters.getKeys()[0]]) +
", " + container.counters.getKeys()[1] + "=" + int(container.counters[container.counters.getKeys()[1]]));
}