count++ can lose updates when multiple threads or goroutines change the same ordinary shared variable. The increment is usually a read, a calculation, and a write—not one indivisible action. An atomic increment makes that counter update indivisible, but it does not automatically synchronize every other value in your program. The exact consequences of an unsynchronized access depend on the language’s memory model.
Why does count++ fail under concurrency?
Suppose count starts at 0 and two workers each increment it. A typical interleaving is:
| # | Preview | Product | Price | |
|---|---|---|---|---|
| 1 |
|
C++ Concurrency in Action | $58.90 | Buy on Amazon |
| 2 |
|
Concurrency in C# Cookbook: Asynchronous, Parallel, and Multithreaded Programming | $31.55 | Buy on Amazon |
| 3 |
|
Grokking Concurrency | $49.99 | Buy on Amazon |
| 4 |
|
Rust Atomics and Locks: Low-Level Concurrency in Practice | $33.13 | Buy on Amazon |
| 5 |
|
Java Concurrency in Practice | $6.54 | Buy on Amazon |
As an Amazon Associate I earn from qualifying purchases.
- Worker A reads 0.
- Worker B reads 0.
- Worker A adds 1 and stores 1.
- Worker B adds 1 and stores 1.
The final value is 1, although two increments ran. This is a lost update: each worker computed from the same old value, and the later store overwrote the earlier one. It illustrates one possible failure, not the only behavior a language may permit for a data race.
Quick wins for a faster PC:
Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Clear out junk files and repair common Windows errorsFree Scan →Is count++ atomic?
Not for an ordinary shared variable. It is a compound read-modify-write operation: load the old value, calculate a new one, then store it. Another worker can intervene between those steps. In C++, for example, an integral std::atomic supports increment and fetch_add; its atomic read-modify-write is specified as one operation, rather than a separate load and store. cppreference: std::atomic
#1 Best Overall
What do atomicity, visibility, and ordering mean?
Atomicity: one update cannot be torn into competing steps
An atomic increment prevents another operation on that atomic object from slipping between the increment’s read and write in a way that loses the update. It solves the single-counter update problem when all relevant accesses use the appropriate atomic operations.
Visibility: another thread can observe published writes
Visibility concerns whether one thread’s writes become observable to another under the language’s synchronization rules. Making one counter increment atomic does not, by itself, publish arbitrary neighboring state.
Ordering: synchronization constrains which operations may be observed first
Memory ordering specifies relationships among operations across threads. It matters when an atomic variable participates in a protocol involving other data. The guarantee comes from the selected language operation and ordering, not merely from the fact that a variable is atomic.
Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Scan for outdated or missing drivers - takes under a minute3Repair Windows errors before they cause bigger problemsDoes volatile make increment thread-safe?
Do not treat volatile as a substitute for an atomic read-modify-write or a lock. The meaning of volatile is language-specific, and it does not generally turn a sequence of reading, adding, and writing into one indivisible increment. Use the concurrency primitive defined by the language for the required guarantee; consult that language’s memory model before relying on a volatile access for synchronization.
Rank #3
Choose a mechanism for the invariant you need
| Mechanism | One counter update indivisible? | Coordinates related state? | Best fit |
|---|---|---|---|
| Ordinary shared increment | No | No synchronization guarantee | Not safe for unsynchronized concurrent updates |
| Atomic increment | Yes, for the atomic operation | Only when the operation’s ordering and protocol establish the needed relationship | A counter whose update is the whole invariant, or a carefully designed atomic protocol |
| Lock or mutex around the update | Yes, for code consistently protected by the same lock | Can protect multiple related values as one critical section | Compound invariants that span counter and other state |
If correctness depends on updating a counter together with another field—for example, a count and the collection it describes—protect the whole invariant with a lock or another design that serializes those changes. Making only the count atomic can leave the combined state inconsistent.
Language examples and memory-model differences
C++: atomic counter when the counter alone needs atomicity
A minimal C++ counter can be declared and incremented as follows:
#include <atomic>
std::atomic<int> count{0};
void record() {
count.fetch_add(1, std::memory_order_relaxed);
}
memory_order_relaxed keeps the counter operation atomic, but adds no ordering or synchronization for unrelated data. That can be suitable when the counter value itself is all the program needs from this operation. If the increment is meant to publish or coordinate other state, choose a protocol and memory order that actually establishes the required relationship; do not infer it from atomicity alone. cppreference: std::atomic
The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Rust: select ordering to match the protocol
Rust’s atomic operations expose explicit orderings. Relaxed provides atomicity for that operation without ordering other operations. Release and Acquire can establish synchronization when an acquire operation observes the relevant release operation. AcqRel combines those roles for a read-modify-write operation. SeqCst additionally places sequentially consistent operations in one total order. These are protocol guarantees, not a ranking where the strongest option is automatically the right design.
Best Value
Rust documents data races involving conflicting unsynchronized access where one access is non-atomic as undefined behavior. Its atomic and ordering documentation describes the available guarantees and their conditions. Rust stable atomic module · Rust stable ordering documentation
Go: serialize shared mutable access
The Go Memory Model’s advice is direct: “Programs that modify data being simultaneously accessed by multiple goroutines must serialize such access.” It names channel operations and synchronization primitives such as sync and sync/atomic as ways to do that. The model also describes happens-before and its DRF-SC guarantee: data-race-free programs behave as if goroutines were interleaved on a single processor. Go Memory Model (identified as version of June 6, 2022)
Java: use Java’s own memory model
Java defines its own thread and memory model in the Java Language Specification. Do not import the exact meaning of a C++ memory order or Go’s race rules into Java; use Java’s rules and APIs for the synchronization you need. Java SE 26 JLS, Chapter 17
When is an atomic counter not enough?
- Several values must change together: use a lock or another protocol that protects the complete invariant.
- The counter signals that other data is ready: choose synchronization with explicit publication and ordering guarantees, not merely an atomic increment.
- Some accesses are atomic and others are ordinary: mixing access styles may still violate the language’s rules. Make all concurrent access follow one coherent synchronization design.
- You are unsure what the language permits: consult its official memory-model documentation; data-race consequences differ by language.
Further reading for Java developers
Java Concurrency in Practice is a Java-specific supplemental book published in 2006. Pearson lists atomic variables, nonblocking algorithms, and the Java Memory Model among its topics. Use it for foundational context, and rely on current Java documentation for current API details. Pearson publisher listing
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




