<<

Sequential Consistency, , and

John Mellor-Crummey

Department of Science Rice University

[email protected]

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 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: —because q is FIFO: —program order implies —together, all of these constraints form a cycle

—contradiction: a cycle orders each operation before itself! 20 Linearizability: a Stronger

• 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 -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: —x is object —m is method —a* are arguments —A is thread • Method response: —t is a termination condition —r* is a sequence of result values

• 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 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