I've heard i isn't thread safe, is i thread-safe?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
If i is a shared ordinary integer, neither i++ nor ++i is thread-safe. The difference between postfix and prefix increment is only about the value returned by the expression. It does not make either operation atomic, and it does not prevent a data race when multiple threads update the same variable without synchronization.
Why Both Forms Are Unsafe on a Shared Non-Atomic Variable
For a normal integer, an increment conceptually involves:
- reading the current value
- computing the incremented value
- writing the new value back
That read-modify-write sequence is exactly what races when two threads do it at the same time.
A simple example is:
If multiple threads run worker concurrently, the final result is undefined behavior in C++ because the code contains a data race.
The same problem exists with counter++.
Prefix Versus Postfix Only Changes the Return Value
The meaning difference is local to the expression:
- '
++iincrements and yields the incremented value' - '
i++increments and yields the old value'
For example:
That distinction matters for expression semantics and sometimes performance in iterator-heavy code, but it does not magically add thread safety.
So the answer to the original question is direct: no, ++i is not a thread-safe replacement for i++ on shared state.
Use std::atomic for Atomic Increments
If the variable is meant to be updated concurrently without a mutex, use std::atomic.
Here, both ++counter and counter++ are atomic operations because counter is an atomic type.
The prefix/postfix distinction still affects the returned value, but thread safety now comes from the atomic type, not from the operator spelling.
Mutexes Are Still a Good Option
If the increment is part of a larger critical section, a mutex is often the better design.
Atomic integers are great for simple counters. Once the update needs to coordinate multiple shared values, a mutex is usually clearer.
volatile Does Not Fix This
A common misconception is that volatile makes shared increments safe. It does not. volatile affects certain optimization behavior, but it does not make a read-modify-write sequence atomic and does not establish the synchronization rules required for safe multithreaded access in normal C++ application code.
Common Pitfalls
- Assuming prefix increment is thread-safe while postfix increment is not is incorrect. Both are unsafe on shared non-atomic variables.
- Focusing on expression syntax instead of data-race rules misses the real issue, which is unsynchronized shared access.
- Using
volatileas a concurrency tool does not solve atomicity or synchronization. - Switching to
std::atomicfor a variable that participates in a larger multi-variable invariant may still be the wrong design; a mutex might be needed. - Testing on one machine and seeing the "right" final count does not prove the code is correct because data-race behavior is still undefined.
Summary
- Neither
i++nor++iis thread-safe for a shared ordinary integer. - The only difference between them is the value returned by the expression.
- Thread safety comes from synchronization, such as
std::atomicor a mutex, not from prefix versus postfix syntax. - Use
std::atomicfor simple concurrent counters. - Use a mutex when the increment is part of a larger critical section.

