Atomic Counters in C++
Our example demonstrates the use of atomic counters in C++. While C++ doesn’t have built-in goroutines, we’ll use threads to showcase concurrent operations on a shared counter.
To compile and run this program:
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’d get undefined behavior due to data races.
In this C++ version:
- We use
std::atomic<uint64_t>
instead of Go’satomic.Uint64
. - We use
std::thread
instead of goroutines. - We use
std::vector<std::thread>
to manage our threads instead of aWaitGroup
. - We use
fetch_add()
for atomic increments instead of Go’sAdd()
. - We use
load()
to safely read the final value.
Note that C++ atomic operations allow specifying memory ordering. In this example, we use std::memory_order_relaxed
for simplicity, but in real-world scenarios, you might need stronger ordering guarantees depending on your specific requirements.
Next, we’ll look at mutexes, another tool for managing state in concurrent programs.