Atomic Counters in Nim
Our primary mechanism for managing state in Nim is communication over channels. However, there are a few other options for managing state. Here we’ll look at using atomic operations for atomic counters accessed by multiple threads.
import atomics
import std/threadpool
var ops = Atomic[uint64](0)
proc incrementCounter() =
for _ in 0..<1000:
ops.atomicInc()
proc main() =
var threads: array[50, Thread[void]]
for i in 0..<50:
createThread(threads[i], incrementCounter)
joinThreads(threads)
echo "ops: ", load(ops)
main()
We use an atomic integer type to represent our (always-positive) counter.
We’ll start 50 threads that each increment the counter exactly 1000 times.
To atomically increment the counter we use atomicInc
.
After all threads are done, we use load
to safely read the final value of the atomic counter.
We expect to get exactly 50,000 operations. Had we used a non-atomic integer and incremented it with regular addition, we’d likely get a different number, changing between runs, because the threads would interfere with each other.
To run the program:
$ nim c -r atomic_counters.nim
ops: 50000
Next, we’ll look at mutexes, another tool for managing state.