an atomic operation and atomicity
The word atomic here means 'indivisible' — it cannot be split or interrupted halfway. An atomic operation is one that the hardware guarantees happens all-at-once from the point of view of every other thread: there is no observable in-between state. Either it has fully happened or it has not happened at all; no other thread can ever catch it midway. This is the smallest building block of safe concurrency, beneath even locks.
Consider the innocent-looking count = count + 1. It is actually three steps: load count into a register, add one, store it back. Two threads running it can interleave so that both load the same old value, both add one, both store — and one increment vanishes. That is a non-atomic read-modify-write. An atomic increment, by contrast, performs the whole load-add-store as one indivisible hardware operation, so no other thread can slip in between; the count is always exactly correct. An atomic variable is a variable (declared in C with _Atomic, e.g. _Atomic int count;, or std::atomic<int> in C++) whose reads, writes, and special operations like atomic_fetch_add are guaranteed atomic and properly synchronized. Crucially, plain loads and stores of an ordinary int are NOT guaranteed atomic in general — and even where a single load is atomic on your hardware, a read-modify-write across two statements is not.
Atomics matter as the foundation everything else is built on: a mutex's lock operation is implemented with an atomic compare-and-swap; lock-free data structures use atomics directly to avoid locks entirely. For simple shared state — a counter, a flag, a single pointer — an atomic variable is often faster and simpler than a mutex, because the synchronization is one CPU instruction rather than a lock/unlock pair. But atomicity has limits: it makes one operation indivisible, not a sequence of them. If your invariant spans two atomic variables, or you need 'check then act' as one unit, a single atomic is not enough and you still need a lock or a compare-and-swap loop.
_Atomic int count = 0; then count++ (or atomic_fetch_add(&count, 1)) from many threads always ends at the right total. With a plain int count, the same loop loses increments to interleaved read-modify-writes.
An atomic increment is one indivisible load-add-store; a plain one is three interruptible steps.
Atomic makes a single operation indivisible — it does NOT make a sequence atomic, and it does not by itself enforce any ordering between unrelated variables beyond what the chosen memory order specifies. Marking a variable volatile is not the same as atomic: volatile prevents some compiler caching but gives no atomicity and no thread synchronization.