skip to content

Linearizability is the usual correctness bar for concurrent data structures. Define it precisely, explain why "the final state is correct" is not a sufficient standard, and contrast it with sequential consistency.

level: seniorimportance: should knowfreq 36%

answer

  1. Effect at one instant between call and return
  2. Resulting order legal for the sequential spec + respects real time
  3. Linearization point; often the successful atomic update
  4. Composes: linearizable parts → linearizable whole
  5. Sequential consistency ignores real time and does not compose

basics

~20 s

An object is linearizable if every operation appears to take effect instantaneously at some instant between its call and its return, and the resulting sequence obeys the object's single-threaded specification. It constrains what concurrent observers can see, not just the end state, and unlike sequential consistency it respects real time and composes.

solid answer

~60 s

**Definition.** For every concurrent execution, you can pick one instant inside each operation's invocation-to-response interval — its *linearization point* — such that ordering all operations by those instants yields a sequential history that is legal for the object's single-threaded specification. Equivalently: the object behaves as if operations happened one at a time, in an order consistent with real time. **Why final state is not enough.** Concurrent programs are observed while running. A queue that momentarily returns the same element to two dequeuers, or a size that never corresponded to any real state, is broken even if the end state balances. Linearizability constrains every intermediate observation, which is what lets you reason about the structure using its sequential contract. **Versus sequential consistency.** Sequential consistency requires some total order consistent with each thread's program order, but ignores real time — an operation may appear to take effect long after it returned. Crucially, linearizability **composes**: a system of individually linearizable objects is linearizable, whereas sequentially consistent components can combine into a non-sequentially-consistent whole.

code

text · 8 lines
text
T1: enq(a) |---------|
T2:            enq(b) |------|
T3:                          deq() -> b |---|
T3:                                       deq() -> a |---|

enq(a) returned before enq(b) was invoked, so a must precede b in
any valid order; a FIFO must then return a first. No ordering of
the linearization points explains this history -> not linearizable.

go deeper

for a junior

Say that each operation should appear to happen at a single instant between its call and its return, so the structure behaves as if operations were one at a time.

for a middle

Add the real-time constraint on non-overlapping operations and the idea of a linearization point, and give an example history that violates it.

for a senior

Contrast it with sequential consistency and serializability, argue linearizability from linearization points, and explain how history-based checkers test it.

for a principal

Decide deliberately where the system needs linearizability versus a weaker, cheaper guarantee, and articulate composability as the reason it is the default bar for concurrent objects.

## The definition, carefully Model an execution as a **history**: a sequence of *invocation* events (the call) and *response* events (the return) for operations on an object, tagged with the thread that issued them. Operations overlap when one's invocation falls between another's invocation and response. A history is **linearizable** if it can be extended (by completing or discarding pending operations) and reordered into a *sequential* history — one where every invocation is immediately followed by its response — such that: 1. the sequential history is **legal** for the object's single-threaded specification (a FIFO queue returns items in insertion order, a counter returns the number of increments so far, and so on); and 2. the order **respects real time**: if operation A returned before operation B was invoked, A precedes B in the sequential order. Operations that overlap in time may be ordered either way — that freedom is what makes concurrency possible — but non-overlapping operations may not be reordered. Equivalently and more usably: each operation has a **linearization point**, an instant between its invocation and its response at which it appears to take effect atomically. An object is linearizable if all its histories are. ## Why this is the useful bar Linearizability is a **safety** property (nothing bad happens) and is entirely separate from **liveness/progress** properties like lock-freedom. A mutex-guarded structure is typically linearizable; so is a good lock-free one. The two axes answer different questions: linearizability asks *is the answer right*, progress asks *will I get an answer*. The practical payoff is that linearizability lets you reason about a concurrent object using its **sequential specification**. You can state invariants like "every enqueued item is dequeued exactly once, in order" and rely on them without enumerating interleavings. The second payoff is **composability** (locality). If every object in a system is individually linearizable, the system as a whole is linearizable. This is unusual and extremely valuable: it means correctness can be established one component at a time. Sequential consistency lacks this property, so components proven correct in isolation can compose into something that is not sequentially consistent. ## Why "the final state is correct" fails End-state reasoning is a batch-processing intuition that does not survive contact with concurrency, for three reasons. 1. **Observations happen during execution.** A stack whose pop briefly returns an element that a concurrent pop also returned is broken the moment a caller acts on it, whatever the final state. 2. **There may be no final state.** Long-running servers never quiesce. 3. **Intermediate states leak into the outside world.** A dequeued message is sent, an allocated identifier is written to a database. There is no undo. A telling example: a size operation implemented by summing per-shard counters while items move between shards can return a number that never corresponded to any real state of the structure at any instant — it is not linearizable even if it is eventually consistent with the true count. Whether that is acceptable is a design decision, but it should be a conscious one. ## Sequential consistency and serializability **Sequential consistency** requires that some total order over all operations exists that is legal for the object and consistent with each thread's own program order. Real time is not constrained, so a write may become visible to other threads arbitrarily later than its return, provided the resulting order is coherent. It is a weaker, cheaper condition often used to describe memory models. Its fatal practical weakness is non-composability. **Serializability** comes from databases and concerns **transactions** — groups of operations, possibly across several objects — appearing to execute in some serial order. It says nothing about real time. **Strict serializability** is roughly the transactional analogue of linearizability: serializable plus real-time order. So linearizability is about single objects and single operations; serializability is about multi-operation transactions. ## Establishing and testing it The usual proof technique is to identify each operation's linearization point and argue that ordering by those points always yields a legal sequential history. In compare-and-set-based algorithms the point is typically the successful atomic update; in lock-based code it is somewhere inside the critical section. Some operations have linearization points that depend on the execution — for instance an emptiness check whose point falls at the read that observed the empty state — which is a sign the proof needs care. Empirically, linearizability checkers generate randomised concurrent histories, record invocations and responses with timestamps, and search for a valid sequential ordering; a failure is a concrete counterexample interleaving. This is far more effective than stress tests that only assert on final state, because it checks exactly the property that end-state assertions miss. ## The interview answer Give the instantaneous-effect definition with the real-time constraint, name the linearization point, say why intermediate observations matter, and close with composability as the reason linearizability rather than sequential consistency is the standard for concurrent objects.

  • Where is the linearization point of a push in a compare-and-set based concurrent stack, and why does identifying it matter?
    It is the successful compare-and-set that installs the new head, because that is the single instant at which the item becomes visible to every other thread; before it, no one can observe the node, and after it, everyone can. Identifying the point turns a proof over arbitrary interleavings into a proof about one atomic instruction per operation. When an operation has no single fixed point — for example an emptiness check whose effective moment depends on what it observed — the argument becomes substantially harder, which is a useful warning sign.
  • Is a linearizable data structure necessarily lock-free, or vice versa?
    Neither implies the other. Linearizability is a safety property about what results are possible; lock-freedom is a liveness property about whether operations complete under adversarial scheduling. A mutex-guarded queue is linearizable and blocking; it is also possible to build a non-blocking structure with weaker guarantees, such as a queue that permits stale reads. You choose the safety bar and the progress guarantee independently.

Think of a shared ledger with a timestamped stamp. Each transaction is stamped at one instant somewhere between when the clerk picked it up and when they handed back the receipt; reading the stamps in order must produce a ledger that a single clerk working alone could have produced.

saying these in an interview costs you the question

  • Defining correctness as the final state being right
  • Confusing linearizability with serializability, which is about multi-operation transactions
  • Believing linearizability implies lock-freedom or any performance property
  • Thinking overlapping operations must be ordered by when they started
  • Assuming that composing sequentially consistent components yields a sequentially consistent system

context