Atomic Counters in D Programming Language
Our primary mechanism for managing state in D is through message passing and synchronization primitives. However, there are other options for managing state as well. In this example, we’ll look at using the core.atomic
module for atomic counters accessed by multiple threads.
import std.stdio;
import std.parallelism;
import core.atomic;
import core.thread;
void main()
{
// We'll use an atomic integer to represent our (always-positive) counter.
shared long ops;
// We'll start 50 tasks that each increment the counter exactly 1000 times.
auto pool = new TaskPool(50);
scope(exit) pool.finish();
foreach (_; 0..50)
{
pool.put(task({
for (int c = 0; c < 1000; c++)
{
// To atomically increment the counter we use atomicOp!"+="
atomicOp!"+="(ops, 1);
}
}));
}
// Wait until all the tasks are done.
pool.finish(true);
// Here no threads are writing to 'ops', but it's safe to atomically
// read a value even while other threads might be updating it.
writeln("ops: ", atomicLoad(ops));
}
We expect to get exactly 50,000 operations. Had we used a non-atomic integer and incremented it with ops++
, we’d likely get a different number, changing between runs, because the threads would interfere with each other. Moreover, we might encounter race conditions.
To run the program:
$ dmd -run atomic_counters.d
ops: 50000
In this D version:
We use
shared long ops
to declare a shared variable that can be safely accessed from multiple threads.Instead of goroutines, we use D’s
std.parallelism
module to create a thread pool and spawn tasks.The
atomicOp!"+="
function is used to atomically increment the counter, which is equivalent to theAdd
method in Go.We use
atomicLoad
to safely read the final value of the counter, which is similar to theLoad
method in Go.The
TaskPool
and itsfinish
method are used to manage and wait for all tasks to complete, serving a similar purpose to Go’sWaitGroup
.
This example demonstrates how to use atomic operations in D to safely manage a counter across multiple threads, achieving the same goal as the original Go program.