Indivisibility as a behavioral guarantee
Atomicity in concurrent programming concerns observable behavior, not the absence of internal implementation steps. Other relevant operations cannot observe or interleave through an intermediate state that the interface excludes. For accesses to a particular atomic object, the language specifies the required indivisibility. It does not promise that the operation takes no time.
One source-code line, one simple-looking assignment, and one atomic operation are therefore different notions. The applicable guarantees come from the language interface, object type, and platform, not source-code brevity. Nor does an atomic operation mean that an enclosing function cannot be interrupted or rescheduled.
Combining observation with update
An atomic load reads a value and an atomic store replaces one. When performed separately, another modification can occur between them. An atomic read-modify-write operation instead combines observation of the old state with its update. In C, operations such as atomic_fetch_add update a suitable atomic integer and return its previous value, directly expressing one shared-counter increment.
Compare-and-exchange compares an object's value with an expected value and conditionally installs a replacement. Its result indicates whether the attempt succeeded. This supports retry algorithms based on an observed old state. Interfaces distinguish weak and strong forms; a failed attempt must not automatically be interpreted as proof that an application condition can never be satisfied.
For C++ integer compare-and-exchange, expected is an input/output parameter: a mismatching comparison writes the observed value back for a subsequent desired-value calculation. The weak form may also fail spuriously despite equal value representations. A single false result therefore does not establish that another thread changed the object. Retry loops must account for expected being updated and recompute their candidate; weak versus strong behavior and success versus failure memory ordering are separate interface choices.
Memory order is a separate dimension
Atomicity constrains an individual operation. Memory ordering additionally constrains relationships between operations as observed by other threads. C and C++ provide forms including relaxed, acquire, release, and sequentially consistent operations. Relaxed atomic access retains indivisibility, but does not by itself establish that unrelated ordinary data have been safely published.
Under the conditions specified by C++, an acquire operation reading a value from the appropriate release sequence establishes synchronization. Sequentially consistent operations have additional total-order requirements. Neither mechanism turns an arbitrary series of operations into one transaction. Stronger ordering changes permitted observations; it does not replace the design of a correct sequence of steps.
A building block, not a complete algorithm
Suppose two threads increment an atomic counter using separate load, calculation, and store operations. Both may read the same old value and subsequently store the same new value. Each access can be atomic while the compound increment still loses an update. An appropriate read-modify-write operation, or locking around the complete update, expresses a different and stronger requirement.
Atomic interfaces and lock-free implementation are also distinct. C++ provides queries for whether operations on an atomic type or object are lock-free, rather than making that assumption universally valid. Initialization before use, consistency across multiple objects, and progress under contention still require separate reasoning. Atomicity is one part of a synchronization protocol, not a certificate that the whole concurrent algorithm is correct.