Proving Linearizability Using Partial Orders (Extended Version)
Artem Khyzha, Mike Dodds, Alexey Gotsman, Matthew Parkinson

TL;DR
This paper introduces a novel proof method for linearizability of concurrent data structures, constructing partial orders to handle future-dependent linearizations, validated on several complex examples.
Contribution
It presents a new proof technique using partial orders and rely-guarantee reasoning to verify linearizability of challenging concurrent data structures.
Findings
Successfully verified Herlihy-Wing queue
Verified TS queue and Optimistic set
Method handles future-dependent linearizations
Abstract
Linearizability is the commonly accepted notion of correctness for concurrent data structures. It requires that any execution of the data structure is justified by a linearization --- a linear order on operations satisfying the data structure's sequential specification. Proving linearizability is often challenging because an operation's position in the linearization order may depend on future operations. This makes it very difficult to incrementally construct the linearization in a proof. We propose a new proof method that can handle data structures with such future-dependent linearizations. Our key idea is to incrementally construct not a single linear order of operations, but a partial order that describes multiple linearizations satisfying the sequential specification. This allows decisions about the ordering of operations to be delayed, mirroring the behaviour of data structure…
Click any figure to enlarge with its caption.
Figure 1
Figure 2
Figure 3
Figure 4
Figure 5
Figure 6
Figure 7
Figure 8Peer Reviews
No public reviews on file for this paper yet. If you reviewed it on a platform where reviews are public (OpenReview, ICLR, NeurIPS, ICML), you can paste yours below so the community can read it here.
Videos
No videos yet. Explain this paper in a talk, walkthrough, or lecture? Add one.
11institutetext: IMDEA Software Institute, Madrid, Spain 22institutetext: University of York, UK 33institutetext: Microsoft Research Cambridge, UK
Proving Linearizability Using Partial Orders
(Extended Version)
Artem Khyzha 11
Mike Dodds 22
Alexey Gotsman 11
Matthew Parkinson 33
Abstract
Linearizability is the commonly accepted notion of correctness for concurrent data structures. It requires that any execution of the data structure is justified by a linearization — a linear order on operations satisfying the data structure’s sequential specification. Proving linearizability is often challenging because an operation’s position in the linearization order may depend on future operations. This makes it very difficult to incrementally construct the linearization in a proof.
We propose a new proof method that can handle data structures with such future-dependent linearizations. Our key idea is to incrementally construct not a single linear order of operations, but a partial order that describes multiple linearizations satisfying the sequential specification. This allows decisions about the ordering of operations to be delayed, mirroring the behaviour of data structure implementations. We formalise our method as a program logic based on rely-guarantee reasoning, and demonstrate its effectiveness by verifying several challenging data structures: the Herlihy-Wing queue, the TS queue and the Optimistic set.
1 Introduction
Linearizability is a commonly accepted notion of correctness of concurrent data structures. It matters for programmers using such data structures because it implies contextual refinement: any behaviour of a program using a concurrent data structure can be reproduced if the program uses its sequential implementation where all operations are executed atomically [4]. This allows the programmer to soundly reason about the behaviour of the program assuming a simple sequential specification of the data structure.
Linearizability requires that for any execution of operations on the data structure there exists a linear order of these operations, called a linearization, such that: (i) the linearization respects the order of non-overlapping operations (the real-time order); and (ii) the behaviour of operations in the linearization matches the sequential specification of the data structure. To illustrate this, consider an execution in Figure 1, where three threads are accessing a queue. Linearizability determines which values the dequeue operation is allowed to return by considering the possible linearizations of this execution. Given (i), we know that in any linearization the enqueues must be ordered before the dequeue, and Enq(1) must be ordered before Enq(3). Given (ii), a linearization must satisfy the sequential specification of a queue, so the dequeue must return the oldest enqueued value. Hence, the execution in Figure 1 has three possible linearizations: [Enq(1); Enq(2); Enq(3); Deq():1], [Enq(1); Enq(3); Enq(2); Deq():1] and [Enq(2); Enq(1); Enq(3); Deq():2]. This means that the dequeue is allowed to return 1 or 2, but not 3.
For a large class of algorithms, linearizability can be proved by incrementally constructing a linearization as the program executes. Effectively, one shows that the program execution and its linearization stay in correspondence under each program step (this is formally known as a forward simulation). The point in the execution of an operation at which it is appended to the linearization is called its linearization point. This must occur somewhere between the start and end of the operation, to ensure that the linearization preserves the real-time order. For example, when applying the linearization point method to the execution in Figure 1, by point (A) we must have decided if Enq(1) occurs before or after Enq(2) in the linearization. Thus, by this point, we know which of the three possible linearizations matches the execution. This method of establishing linearizability is very popular, to the extent that most papers proposing new concurrent data structures include a placement of linearization points. However, there are algorithms that cannot be proved linerizable using the linearization point method.
In this paper we consider several examples of such algorithms, including the time-stamped (TS) queue [7, 2]—a recent high-performance data structure with an extremely subtle correctness argument. Its key idea is for enqueues to attach timestamps to values, and for these to determine the order in which values are dequeued. As illustrated by the above analysis of Figure 1, linearizability allows concurrent operations, such as Enq(1) and Enq(2), to take effect in any order. The TS queue exploits this by allowing values from concurrent enqueues to receive incomparable timestamps; only pairs of timestamps for non-overlapping enqueue operations must be ordered. Hence, a dequeue can potentially have a choice of the “earliest” enqueue to take values from. This allows concurrent dequeues to go after different values, thus reducing contention and improving performance.
The linearization point method simply does not apply to the TS queue. In the execution in Figure 1, values 1 and 2 could receive incomparable timestamps. Thus, at point (A) we do not know which of them will be dequeued first and, hence, in which order their enqueues should go in the linearization: this is only determined by the behaviour of dequeues later in the execution. Similar challenges exist for other queue algorithms such as the baskets queue [12], LCR queue [16] and Herlihy-Wing queue [11]. In all of these algorithms, when an enqueue operation returns, the precise linearization of earlier enqueue operations is not necessarily known. Similar challenges arise in the time-stamped stack [2] algorithm. We conjecture that our proof technique can be applied to prove the time-stamped stack linearizable, and we are currently working on a proof.
In this paper, we propose a new proof method that can handle algorithms where incremental construction of linearizations is not possible. We formalise it as a program logic, based on Rely-Guarantee [13], and apply it to give simple proofs to the TS queue [2], the Herlihy-Wing queue [11] and the Optimistic Set [17]. The key idea of our method is to incrementally construct not a single linearization of an algorithm execution, but an abstract history—a partially ordered history of operations such that it contains the real-time order of the original execution and all its linearizations satisfy the sequential specification. By embracing partiality, we enable decisions about order to be delayed, mirroring the behaviour of the algorithms. At the same time, we maintain the simple inductive style of the standard linearization-point method: the proof of linearizability of an algorithm establishes a simulation between its execution and a growing abstract history. By analogy with linearization points, we call the points in the execution where the abstract history is extended commitment points.
The extension can be done in several ways: (1) committing to perform an operation; (2) committing to an order between previously unordered operatons; (3) completing an operation.
Consider again the TS queue execution in Figure 1. By point (A) we construct the abstract history in Figure 2(a). The edge in the figure is mandated by the real-time order in the original execution; Enq(1) and Enq(2) are left unordered, and so are Enq(2) and Enq(3). At the start of the execution of the dequeue, we update the history to the one in Figure 2(b). A dashed ellipse represents an operation that is not yet completed, but we have committed to performing it (case 1 above). When the dequeue successfully removes a value, e.g., 2, we update the history to the one in Figure 2(c). To this end, we complete the dequeue by recording its result (case 3). We also commit to an order between the Enq(1) and Enq(2) operations (case 2). This is needed to ensure that all linearizations of the resulting history satisfy the sequential queue specification, which requires a dequeue to remove the oldest value in the queue.
We demonstrate the simplicity of our method by giving proofs to challenging algorithms that match the intuition for why they work. Our method is also similar in spirit to the standard linearization point method. Thus, even though in this paper we formulate the method as a program logic, we believe that algorithm designers can also benefit from it in informal reasoning, using abstract histories and commitment points instead of single linearizations and linearization points.
2 Linearizability, Abstract Histories and Commitment Points
Preliminaries. We consider a data structure that can be accessed concurrently via operations in several threads, identified by . Each operation takes one argument and returns one value, both from a set ; we use a special value to model operations that take no argument or return no value. Linearizability relates the observable behaviour of an implementation of such a concurrent data structure to its sequential specification [11]. We formalise both of these by sets of histories, which are partially ordered sets of events, recording operations invoked on the data structure. Formally, an event is of the form . It includes a unique identifier and records an operation called by a thread with an argument , which returns a value . We use the special return value for events describing operations that have not yet terminated, and call such events uncompleted. We denote the set of all events by . Given a set , we write if and let consist of all completed events from . We let denote the set of all identifiers of events from . Given an event identifier , we also use , , and to refer to the corresponding components of the tuple .
Definition 1
A *history111 For technical convenience, our notion of a history is different from the one in the classical linearizability definition [11], which uses separate events to denote the start and the end of an operation. We require that be an interval order, we ensure that our notion is consistent with an interpretation of events as segments of time during which the corresponding operations are executed, with ordering before if finishes before starts [5]. * is a pair , where is a finite set of events with distinct identifiers and is a strict partial order (i.e., transitive and irreflexive), called the real-time order. We require that for each :
- •
events in are totally ordered by :
;
- •
only maximal events in can be uncompleted:
;
- •
is an interval order:
.
We let be the set of all histories. A history is sequential, written , if and is total on .
Informally, means that the operation recorded by completed before the one recorded by started. The real-time order in histories produced by concurrent data structure implementations may be partial, since in this case the execution of operations may overlap in time; in contrast, specifications are defined using sequential histories, where the real-time order is total.
Linearizability. Assume we are given a set of histories that can be produced by a given data structure implementation (we introduce a programming language for implementations and formally define the set of histories an implementation produces in §5). Linearizability requires all of these histories to be matched by a similar history of the data structure specification (its linearization) that, in particular, preserves the real-time order between events in the following sense: the real-time order of a history is preserved in a history , written , if and .
The full definition of linearizability is slightly more complicated due to the need to handle uncompleted events: since operations they denote have not terminated, we do not know whether they have made a change to the data structure or not. To account for this, the definition makes all events in the implementation history complete by discarding some uncompleted events and completing the remaining ones with an arbitrary return value. Formally, an event can be completed to an event , written , if , , , and either or . A history can be completed to a history , written , if , , and .
Definition 2
A set of histories (defining the data structure implementation) is linearized by a set of sequential histories (defining its specification), written , if .
Let be the set of sequential histories defining the behaviour of a queue with . Due to space constraints, we provide its formal definition in the extended version of this paper [14], but for example, [Enq(2); Enq(1); Enq(3); Deq():2] and [Enq(1); Enq(2); Enq(3); Deq():2] .
Proof method. In general, a history of a data structure ( in Definition 2) may have multiple linearizations () satisfying a given specification . In our proof method, we use this observation and construct a partially ordered history, an abstract history, all linearizations of which belong to .
Definition 3
A history is an abstract history of a specification given by the set of sequential histories if , where . We denote this by .
We define the construction of an abstract history by instrumenting the data structure operations with auxiliary code that updates the history at certain commitment points during operation execution. There are three kinds of commitment points:
When an operation with an argument starts executing in a thread , we extend by a fresh event , which we order in after all events in . 2. 2.
At any time, we can add more edges to . 3. 3.
By the time an operation finishes, we have to assign its return value to its event in .
Note that, unlike Definition 2, Definition 3 uses a particular way of completing an abstract history , which just discards all uncompleted events using . This does not limit generality because, when constructing an abstract history, we can complete an event (item 3) right after the corresponding operation makes a change to the data structure, without waiting for the operation to finish.
In §6 we formalise our proof method as a program logic and show that it indeed establishes linearizability. Before this, we demonstrate informally how the obligations of our proof method are discharged on an example.
3 Running Example: the Time-Stamped Queue
We use the TS queue [7] as our running example. Values in the queue are stored in per-thread single-producer (SP) multi-consumer pools, and we begin by describing this auxiliary data structure.
SP pools. SP pools have well-known linearizable implementations [7], so we simplify our presentation by using abstract pools with the atomic operations given in Figure 3. This does not limit generality: since linerarizability implies contextual refinement (§1),
properties proved using the abstract pools will stay valid for their linearizable implementations. In the figure and in the following we denote irrelevant expressions by .
The SP pool of a thread contains a sequence of triples , each consisting of a unique identifier , a value enqueued into the TS queue by the thread and the associated timestamp . The set of timestamps is partially ordered by , with a distinguished timestamp that is greater than all others. We let be the set of states of an abstract SP pool. Initially all pools are empty. The operations on SP pools are as follows:
- •
insert(t,v) appends a value v to the back of the pool of thread t and associates it with the special timestamp ; it returns an identifier for the added element.
- •
setTimestamp(t,p,) sets to the timestamp of the element identified by p in the pool of thread t.
- •
getOldest(t) returns the identifier and timestamp of the value from the front of the pool of thread t, or if the pool is empty.
- •
remove(t,p) tries to remove a value identified by p from the pool of thread t. Note this can fail if some other thread removes the value first.
Separating insert from setTimestamp and getOldest from remove in the SP pool interface reduces the atomicity granularity, and permits more efficient implementations.
The reference list from the paper itself. Each links out to its DOI / PubMed record.
- 1[1] T. Dinsdale-Young, M. Dodds, P. Gardner, M. J. Parkinson, and V. Vafeiadis. Concurrent abstract predicates. In ECOOP , 2010.
- 2[2] M. Dodds, A. Haas, and C. M. Kirsch. A scalable, correct time-stamped stack. In POPL , 2015.
- 3[3] B. Dongol and J. Derrick. Verifying linearizability: A comparative survey. ar Xiv Co RR , 1410.6268, 2014.
- 4[4] I. Filipovic, P. W. O’Hearn, N. Rinetzky, and H. Yang. Abstraction for concurrent objects. Theoretical Computer Science , 2010.
- 5[5] P. C. Fishburn. Intransitive indifference with unequal indifference intervals. Journal of Mathematical Psychology , 7, 1970.
- 6[6] A. Gotsman and H. Yang. Linearizability with ownership transfer. In CONCUR , 2012.
- 7[7] A. Haas. Fast Concurrent Data Structures Through Timestamping . Ph D thesis, University of Salzburg, 2015.
- 8[8] S. Heller, M. Herlihy, V. Luchangco, M. Moir, W. N. Scherer, and N. Shavit. A lazy concurrent list-based set algorithm. In OPODIS , 2005.
