Sequential Consistency, Linearizability, and Serializability
John Mellor-Crummey
Department of Computer Science Rice University
COMP 422 Lecture 21 3 April 2007 Topics for Today
Reasoning about concurrent operations on objects • Objects, methods, concurrency and correctness • Sequential consistency • Linearizability —locality property —non-blocking property • Serializability
2 Objects
• Object —container for data —methods for manipulating state • Example: queue object class queue { private: qelement *head qelement *tail data public: void enq(qelement *x) qelement *deq() methods void queue() void ~queue() }
intuitive notion of queue state: seq of items, possibly empty 3 Informal Method Description
Effects • Modify object state —if object is in X state before method is invoked, it will be in Y state when the method returns • Yield result —the method will return a value or throw an exception
4 Formalizing Method Descriptions
• Pre-condition — object state upon method invocation • Post-condition —object state upon method completion —exception or return value of method (if any)
• Queue example —void enq(qelement *x) – pre-condition: queue state is some seq of elements q (possibly empty) – post-condition: queue state is q . x, where . denotes concatenation —qelement *deq() two possibilities (1) pre-condition: if queue state is x . q, where x is an element post-condition: queue state is q, deq returns x (2) pre-condition: else queue state is empty post-condition: deq throws an exception and queue remains empty 5 Properties of Objects and Methods
• Object state —well-defined between method calls • Method interactions —characterized by each method’s side effects upon object state • Pre- and post- conditions —describe state before and after method invocations —ignore intermediate states while method invocation is active —adequately describe operation in a sequential computation
6 Modeling Method Calls
Method calls take time • Model method execution as an interval
q.enq(x)
begin with an invocation event end with a response event • Method calls by a single thread may not overlap —displayed along a horizontal line
Thread 0: q.enq(y) q.deq(): z
Thread 1: q.enq(x)
• Method calls by concurrent threads may overlap
7 What about Method Concurrency?
• What happens when method invocations overlap in time? —example q.enq(x)
q.enq(y)
—operation “order” is ill-defined – which item will be dequeued first? • Can we still describe method effects using pre- and post- conditions, or must we worry about interleavings?
8 What about Object State?
• Single-threaded programs —meaningful object states need only exist between method operations • Concurrent programs —overlapping method calls may be active at every instant – may never be between method calls —method invocation can encounter object state reflecting incomplete effects of other concurrent method calls
9 Correctness for Concurrent Objects
• What does it mean for a concurrent object to be correct? —“equivalent” to sequential behavior • What is the right notion of equivalence for correctness?
10 What is Correct Behavior?
Example: reading and writing a register Register r; methods read() and write(x)
r.write(8)
r.write(1) r.read(): 9
(1) Method calls appear to happen instantaneously in some seq order
r.write(0) r.write(1) r.read(): 0
(2) Method calls should appear to take effect in program order
(1) + (2) = sequential consistency
11 Sequential Consistency
• Methods act as if they occurred —in some seq order —consistent with program order • May be more than one order that satisfies this condition
q.enq(1) q.deq(): 2
q.enq(2) q.deq(): 1 —alternatives enq(1), enq(2), deq(): 1, deq(): 2 enq(2), enq(1), deq(): 2, deq(): 1
—both consistent with method call’s program order —either one suffices to show the history is sequentially consistent 12 Consistency Subtleties
Example: reading and writing two memory locations
Registers m1 and m2; methods read() and write(x)
m1.write(1) m2.read(): 0
m2.write(1) m1.read(): 0
• Each thread’s observations — individually consistent with a sequential ordering for own operations – in program order – before other thread’s calls • Overall history is not sequentially consistent — perceived orderings of the two threads’ events are incompatible
13 Consistency In Modern Architectures
Example: reading and writing two objects
Objects x1 and x2; methods read() and write(x)
x1.write(1) x2.read(): ?2
x2.write(1) x1.read(): ?1 Cases
• x1 and x2 are registers — two processes each write to a separate register and then read from the other — one thread will observe the other thread’s write – the flag principle: basis for nearly all synchronization algorithms → sequentially consistent
• x1 and x2 are memory locations — 2 processes write to 2 memory locations, read from each other’s — writes to memory are buffered: may take 100+ cycles — read can pass a buffered write — in some cases, neither thread may observe the other thread’s write → not sequentially consistent 14 Coping With Memory Consistency
• Memory is not sequentially consistent —processors can reorder reads and writes in complex ways – flexibility = performance —usually, no one knows the difference! – difference only visible with synchronization variables • How do programs cope? —ask for sequential consistency explicitly when necessary! – when must order be maintained? when others can observe the difference [Shasha, Snir; Efficient and correct execution of parallel programs that share memory. ACM TOPLAS, 10(2):282-312, April 1988] – h/w support: memory barrier or fence instructions explicitly propagate value to/from memory to ensure consistency – programmer/compiler: insert fences/barriers where necessary implement sequential consistency on demand only
15 Sequential Consistency vs. Real-time Order
Example: queue operations • Queue q; methods enq(x) and deq() q.enq(0) q.deq(): 1
q.enq(1) • This history violates expectations about FIFO queue behavior —method enq(0) finishes before deq() that yields 1 —although 1 enqueued after 0, it is dequeued before • This history is sequentially consistent! —2 enqueues are unrelated by program order —sequential consistency is free to reorder them!
16 Pondering Consistency
• Should it be legal to reorder method calls that don’t overlap? • Consider the following —deposit paycheck on Monday —buy groceries with a check on Friday • Expectations —funds from paycheck deposit are available for payment
17 Impact of Reordering
• A correctness property P is local if —whenever each object in the system satisfies P —the system satisfies P • Locality is important for constructing large software systems —need modularity for design tractability – design, implement, and prove components independently – components: distinguish between interfaces and implementations if concurrent object’s interface states that it is a FIFO queue users shouldn’t need to know about implementation —composing correct components should lead to a correct system • Does composing sequentially consistent components lead to a correct system? —sadly, no!
18 Composing Sequential Consistent Histories
Example: queue operations • Queues p, q; methods enq(x) and deq() • Consider the the following histories
A p.enq(0) q.enq(0) p.deq(): 1
B q.enq(1) p.enq(1) q.deq(): 0
—composition of two sequentially consistent histories of the form
q.enq(0) q.deq(): 1
q.enq(1)
19 Sequential Consistency is not Local
A p.enq(0) q.enq(0) p.deq(): 1
B q.enq(1) p.enq(1) q.deq(): 0
• Each individual queue history is sequentially consistent (shown previously) • Composite history for two queues is not sequentially consistent • Proof: assume methods can be reordered to form seq consistent history —because p is FIFO:
• Sequential consistency —method calls appear to happen instantaneously in some seq order —method calls should appear to take effect in program order • Linearizability [Herlihy, Wing, TOPLAS, 1990] —each method call appears to happen instantaneously at some point between its invocation and response —method calls should appear to take effect in program order • Relating the two models —every linearizable history is sequentially consistent —a sequentially consistent history is not necessarily linearizable
preserves real-time order of method calls
21 Examples q.enq(0) q.deq(): 1
q.enq(1) q.deq(): 0
linearizable
q.enq(0) q.deq(1)
q.enq(1)
not linearizable
22 Another Example
q.enq(0)
q.deq(): 0
linearizable
23 Multiple Possible Orders are OK q.enq(0) q.deq(): 1
q.enq(1) q.deq(): 0
linearizable
q.enq(0) q.deq(): 1
q.enq(1) q.deq(): 0
linearizable
24 A Lock-free Queue for Two Threads class queue { int head = 0; int tail = 0 item **items = new *item[QSIZE] void enq(item *x) { while (this.tail - this.head == QSIZE){} this.items[this.tail % QSIZE] = x; this.tail++ } enqueue takes effect here item *deq() { while (this.tail == this.head) {} item *x = this.items[this.head % QSIZE] this.head++ dequeue takes effect here return x } }
Note: one thread is producer, other is consumer else trouble!
25 What about Corner Cases?
• How do we consider a method call that does not return? • Must define everything precisely
26 Precise Definitions
• Method invocation:
• History: finite sequence of invocation and response events • Subhistory: subsequence of events in a particular history
27 Invocations and Methods
• A response matches an invocation if —object names agree —thread names agree • Method call: pair consisting of —invocation —next matching response • Invocation is pending in a history if no matching response follows the invocation • A method is total if it is defined for every object state —e.g. what happens with a dequeue of an empty queue? —otherwise, it is partial
28 Properties of Histories
• If H is a history, complete(H) is the subsequence of H consisting of all matching invocations and responses —ignores pending methods • A history H is sequential if —1st event of H is an invocation —each invocation, except perhaps last, is immediately followed by a matching response • Thread subhistory, H|P (H at P) of a history H is the subsequence of all events in H whose thread name is P • Object subhistory, H|x is similar • Two histories H and H’ are equivalent if for every thread A, H|A = H’|A • History H is well-formed if each thread subhistory H|A of H is sequential —rule out nonsense
29 Ordering Relationships
• Irreflexive partial order → on a set X is a relation that is —irreflexive: for all x in X, it is never true that x → x —transitive: for all x, y, z in X, if x → y and y → z, then x → z • Total order < on a set X is a relation that is —a partial order, and —for all distinct x, y ∈ X, either x < y or y < x
• Total order vs. partial order —any partial order can be extended to be a total order – if → is a partial order on a set X, then there exists a total order on X such that if x → y, x < y
30 Precedence of Method Operations
• If method call m0 finishes before method call m1 starts, we say m0 precedes m1 in H, or m0 →H m1
—Note: if H is a sequential history, then →H is a total order • Given a history H and an object x such that H|x contains method calls m0 and m1, we say that m0 →x m1 if m0 precedes m1 in H|x
— →x is a total order
• A property is local if all objects collectively satisfy it if each individual object satisfies it
31 Linearizability is a Local Property
• Theorem: H is linearizable if and only if for each object x, H|x is linearizable • Proof: see Herlihy and Shavit Chapter 4 for the details
32 Why Linearizability?
• Naïve reasoning about concurrent objects —must consider all possible multi-way interactions of methods • Linearizability —methods still described by pre- and post- conditions
33 Linearizability: Non-blocking Property
• A pending invocation of a total method is never required for another pending invocation to complete
34 Serializability
• A history is serializable if it is equivalent to one in which the transactions appear to execute sequentially without interleaving • A history is strictly serializable if the transactions’ order in the sequential history is compatible with their precedence order —if every method call of transaction A precedes every method call of transaction B, then A is serialized before B
• Linearizability is a special case of strict serializability —transaction = a single method applied to a single object • Neither serializability nor strict serializability is a local property! • Both are blocking properties 35 Serializability and Transactions
Consider transactions A and B
A x.read(): 0 y.write(1)
B y.read(): 0 x.write(1)
• Each transaction’s own history is serializable • Neither can go first! —both unable to complete without violating serializability —at least one must roll back and restart
36 Linearizability vs. Serializability
Appropriate for different problem domains • Linearizability for generalized individual shared object implementations • Serializability for database systems — must be easy for application programmers to preserve complex application-specific invariants spanning multiple objects
37 References
• M. Herlihy, J. Wing. Linearizability: A correctness condition for concurrent objects. ACM Transactions on Programming Languages and Systems 12(3):463-492, 1990. • M. Herlihy and Nir Shavit. Multiprocessor Synchronization and Concurrent Data Structures. Chapter 4: Sequential Consistency and Linearizability. 2005. Unpublished Manuscript. http://www.cs.brown.edu/courses/cs176/linear.pdf • M. Herlihy and Nir Shavit. Concurrent Objects and Linerizability. 2005. http://www.cs.brown.edu/courses/cs176/linear.slides.pdf
38 Linearizability
• Intuition —every concurrent history is “equivalent” to a sequential history so that – if a method call A precedes a method call B, then A must “take effect” first – if two method calls overlap, then their order is ambiguous we can choose any order that makes sense • Formal definition —a history H is linearizable if it can be extended (by appending 0 or more response events) to a history H’ such that – complete(H) is equivalent to a legal sequential history S, and – If method call m0 precedes method call m1 in H, then it does in S as well • Notes —S is a linearization of H; H may have multiple linearizations —extending H to H’ captures the idea that not all method calls in H may be complete – H may contain invocations without matching responses
39 40 Properties of Objects
41