Hardware FixRecommendedDevice not working? Your driver may be the problemCheck updates for common hardware issues.Fix DriversOctober DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsClean PCRecommendedOne scan can reveal what keeps slowing WindowsLook for cleanup and repair opportunities.Run Scan×
Skip to content
World desk8 min

Concurrency Programming (5): Atomics—Atomicity, Visibility, and Ordering at the Language Level

Atomic operations protect particular accesses, not every nearby read or write. Learn how atomicity, synchronization, visibility, and ordering differ across Rust, Java VarHandles, and LLVM.
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

An atomic operation makes a particular access indivisible under its language’s concurrency rules. It does not, by itself, make nearby non-atomic accesses safe or guarantee that another thread immediately sees them. To share data safely, distinguish atomicity (what an operation protects), synchronization and visibility (when one thread’s writes are guaranteed to be observable by another), and ordering (which relationships between operations the language requires).

What an atomic operation guarantees—and what it does not

An atomic operation acts on an atomic location as a single indivisible operation according to the language’s memory model. Other threads cannot observe that operation as a partially completed update. Atomic APIs also define how operations on the same location relate to one another; the details depend on the language and operation.

As an Amazon Associate I earn from qualifying purchases.

That guarantee is limited to the atomic access and its specified ordering. Making a counter atomic does not automatically protect other fields, publish an object, or turn ordinary reads and writes into atomic accesses. If threads access the same ordinary memory without the synchronization required by their language, the program may still have a data race even if an atomic variable appears nearby.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  • Atomicity: Is this access indivisible under the applicable model?
  • Synchronization and visibility: Has a relationship been established that guarantees another thread can observe prior writes?
  • Ordering: What constraints does the model place on how this operation relates to other operations?

These concepts are related, but they are not interchangeable. In particular, “atomic” does not mean “instantly visible everywhere.”

What does relaxed ordering mean?

In Rust, Ordering::Relaxed requests atomic access without using that operation to synchronize surrounding data. The operation is still atomic, and operations on a given atomic location retain the location-level guarantees required by Rust’s model. But a relaxed operation alone does not establish a happens-before relationship that publishes unrelated ordinary writes to another thread.

For example, if multiple threads update an atomic counter only to maintain a count, and no other data is meant to be communicated through that counter, relaxed operations may express the needed guarantee. If a thread uses the counter as a signal that other data is ready, relaxed ordering alone is not enough to safely publish that data.

LLVM’s LangRef calls its corresponding ordering monotonic and describes it as matching C and C++ memory_order_relaxed. It provides per-location modification ordering, not one global order across separate locations. LLVM IR is a compiler representation, however—not a replacement for the source language’s rules.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

When do acquire and release establish visibility?

Acquire and release are commonly used as a pair to publish data. A thread first writes ordinary data, then performs a release operation on an atomic. Another thread performs an acquire operation on that atomic and observes the relevant release publication. When the language’s synchronization conditions are met, the writes sequenced before the release happen before the acquiring thread’s subsequent accesses. That relationship is what makes the earlier writes safely observable; it is not a promise of instantaneous propagation to every thread.

  1. The publishing thread initializes or updates the data, following the language’s rules for that data.
  2. It performs a release operation on a synchronization atomic after those writes.
  3. The receiving thread performs an acquire operation on that atomic and observes the publication that forms the required synchronization relationship.
  4. It then accesses the published data, with the acquire/release relationship ordering those accesses after the earlier writes.

The phrase “observes the publication” matters. Merely performing an acquire operation on an atomic does not make it synchronize with every release operation on that location. Which operation is observed, and whether the required relationship exists, are determined by the language’s memory model. Correct code must also ensure the data is accessed in a way that does not create a separate data race.

In Rust, the standard library documents ordering in terms of interaction with happens-before and says Rust’s atomics currently follow C++20 atomic rules, without consume ordering, with differences arising from Rust’s access-based model. Rustonomicon presents acquire and release as the usual synchronization pair. In Java’s Java SE 16 VarHandle API, acquire reads and matching release writes provide ordering as documented for those access modes; consult the applicable JDK and Java specification when targeting a different release.

How Rust ordering options differ

Rust exposes Relaxed, Acquire, Release, AcqRel, and SeqCst in its atomic APIs. The ordering is selected per operation, and not every ordering is valid for every operation kind: for example, a load cannot be a release operation, and a store cannot be an acquire operation.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Rust ordering What it is for What not to infer
Relaxed Atomic access when no synchronization of surrounding data is needed. It does not publish unrelated writes or create acquire/release synchronization by itself.
Acquire Typically an atomic load intended to pair with a release publication it observes. It does not synchronize with an arbitrary release merely because both operations use the same atomic location.
Release Typically an atomic store that orders prior writes before a publication. It does not by itself make a receiver observe the publication; a qualifying acquire relationship is needed.
AcqRel An atomic read-modify-write operation that needs both acquire and release behavior. It is not a general setting for ordinary loads or stores, nor does it remove the need to establish the intended synchronization relationship.
SeqCst Sequentially consistent atomic operations, with a stronger ordering model that is often easier to reason about. It does not excuse data races or replace the language’s rules for non-atomic accesses.

Rustonomicon describes sequential consistency as the strongest ordering exposed by Rust and offers a useful intuition: data-race-free programs using only sequentially consistent atomics and data accesses admit a single global execution that all threads agree on. That intuition is about the documented model; weaker orderings are not arbitrary permission for the compiler or processor to do anything.

What sequential consistency adds

Sequential consistency (Rust’s SeqCst) gives participating operations stronger ordering constraints than relaxed or acquire/release operations. It can make a concurrent algorithm easier to reason about because the relevant sequentially consistent operations fit into a single order consistent with each thread’s program order.

It is not a universal “make this thread-safe” switch. It cannot make conflicting unsynchronized non-atomic accesses legal, and it does not make every operation in a program part of the same sequentially consistent order. The rules for operations with other orderings and for ordinary data still matter.

Rustonomicon recommends starting with sequential consistency when unsure, then treating any later move to weaker orderings as a proof obligation. A downgrade is correct only if the algorithm still has the synchronization and ordering relationships it relies on.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

How the terminology differs across Rust, Java, and LLVM

Concern Rust Java VarHandle (Java SE 16 documentation) LLVM IR
Access modes or orderings Relaxed, Acquire, Release, AcqRel, and SeqCst; Rust does not expose consume ordering. Plain, opaque, acquire, release, volatile, and atomic update access modes, grouped by operation type. IR orderings including unordered, monotonic, acquire, release, acq_rel, and seq_cst.
Synchronization Ordering participates in happens-before under Rust’s model. Matching acquire reads and release writes provide ordering; volatile operations are totally ordered with respect to one another. Acquire and release operations may form synchronization; monotonic corresponds to relaxed semantics.
Important boundary Conflicting, unsynchronized non-atomic accesses can constitute a data race and undefined behavior. Mixed access modes require care; a VarHandle access mode can override declaration-site ordering. LLVM IR implements language models; the source-language specification governs source-level correctness.

These are related concepts, not interchangeable APIs. Java’s VarHandle documentation also groups modes across reads, writes, atomic updates, numeric updates, and bitwise updates. Its warnings about mixing access modes are important: do not assume that a field’s declaration alone determines the ordering of every VarHandle access.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Why processor behavior is not the language contract

A concurrent program may appear to work on one processor because that processor’s behavior happens to be stronger than the ordering the code requests. That observation does not prove the program is correct under the language model. The compiler can also optimize according to the language’s guarantees, and another processor may expose assumptions that went unnoticed.

Rustonomicon specifically cautions that weaker-ordering code can appear to work on strongly ordered hardware while remaining incorrect. Testing on weakly ordered hardware can help uncover problems, but no hardware test substitutes for reasoning from the language contract. Correctness is defined by the source language and its atomic API; processor behavior is an implementation detail constrained by that contract.

Practical checks before choosing an ordering

  • Name the language and API. “Acquire” and “volatile” do not have identical semantics across Rust, Java, C++, or LLVM IR.
  • Identify what must be atomic. An atomic counter does not protect a separate ordinary field.
  • Decide whether the atomic is also communicating. If it only tracks an independent value, relaxed may suffice. If it signals that other data is ready, establish the required synchronization.
  • Trace the synchronization pair. Identify the release, the acquire, and why the acquire observes the relevant publication under that language’s rules.
  • Check all accesses to adjacent data. Confirm that no conflicting unsynchronized non-atomic access remains.
  • Prefer the simpler proof when uncertain. Sequential consistency is often easier to reason about; weakening it requires a separate correctness argument.
  • Check target support and API constraints. LLVM’s concurrency guide notes that some wide atomic operations may not be supported on a target and code generation can fail for unsupported operations. Do not assume every atomic is lock-free on every target.

Do not use volatile as a substitute for synchronization

“Volatile” is not a portable synonym for “atomic” or “thread-safe.” In LLVM IR, volatile and atomic are orthogonal properties. Java VarHandle’s volatile modes have specific documented ordering behavior, but that does not make Java’s rules universal. In C and C++, volatile does not provide the inter-thread synchronization needed to publish ordinary data. Use the language’s documented atomic and synchronization facilities for the concurrency guarantee you need.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

How to reason about a concurrent access

For each shared value, ask three questions separately: what operation must be indivisible, what writes another thread must be guaranteed to observe, and what ordering between operations the algorithm needs. Then apply the data-race rules and API of the language in use. This avoids the common mistake of treating a single atomic variable as if it automatically made the surrounding program safe.

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.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Redmond desk20 min
    How to create a link to File or Folder in Windows 11Windows 11 gives you several ways to point to a file or folder without moving or duplicating it. You can create a desktop shortcut,…
Recommended PC Tool
Recommended PC Tool
Outdated Drivers Are Slowing You DownFree scan - exact matches
Windows Errors? Fix Them Before They SpreadFree repair scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.