Download presentation
Presentation is loading. Please wait.
1
Art of Multiprocessor Programming 1 Universality of Consensus Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit Modified by Rajeev Alur For CIS 640 University of Pennsylvania
2
Art of Multiprocessor Programming 2 Turing Computability A mathematical model of computation Computable = Computable on a T-Machine 011010 1
3
Art of Multiprocessor Programming 3 Shared-Memory Computability Model of asynchronous concurrent computation Computable = Wait-free/Lock-free computable on a multiprocessor cache shared memory cache
4
Art of Multiprocessor Programming 4 Consensus Hierarchy 1 Read/Write Registers, Snapshots… 2 getAndSet, getAndIncrement, … ∞ compareAndSet,…......
5
Art of Multiprocessor Programming 5 Who Implements Whom? 1 Read/Write Registers, Snapshots… 2 getAndSet, getAndIncrement, … ∞ compareAndSet,…...... no
6
Art of Multiprocessor Programming 6 Hypothesis 1 Read/Write Registers, Snapshots… 2 getAndSet, getAndIncrement, … ∞ compareAndSet,…...... yes?
7
Art of Multiprocessor Programming 7 Theorem: Universality Consensus is universal From n-thread consensus build a –Wait-free –Linearizable –n-threaded implementation –Of any sequentially specified object
8
Art of Multiprocessor Programming 8 Proof Outline A universal construction –From n-consensus objects –And atomic registers Any wait-free linearizable object –Not a practical construction –But we know where to start looking …
9
Art of Multiprocessor Programming 9 Like a Turing Machine This construction –Illustrates what needs to be done –Optimization fodder Correctness, not efficiency
10
Art of Multiprocessor Programming 10 A Generic Sequential Object public interface SeqObject { public abstract Response apply(Invocation invoc); }
11
Art of Multiprocessor Programming 11 A Generic Sequential Object public interface SeqObject { public abstract Response apply(Invocation invoc); } Push:5, Pop:null
12
Art of Multiprocessor Programming 12 Invocation public class Invoc { public String method; public Object[] args; }
13
Art of Multiprocessor Programming 13 Invocation public class Invoc { public String method; public Object[] args; } Method name
14
Art of Multiprocessor Programming 14 Invocation public class Invoc { public String method; public Object[] args; } Arguments
15
Art of Multiprocessor Programming 15 A Generic Sequential Object public interface SeqObject { public abstract Response apply(Invocation invoc); }
16
Art of Multiprocessor Programming 16 A Generic Sequential Object public interface SeqObject { public abstract Response apply(Invocation invoc); } OK, 4
17
Art of Multiprocessor Programming 17 Response public class Response { public Object value; }
18
Art of Multiprocessor Programming 18 Response public class Response { public Object value; } Return value
19
Art of Multiprocessor Programming 19 Universal Concurrent Object public interface SeqObject { public abstract Response apply(Invocation invoc); } A universal concurrent object is linearizable to the generic sequential object
20
Art of Multiprocessor Programming 20 Start with Lock-Free Universal Construction First Lock-free: infinitely often some method call finishes. Then Wait-Free: each method call takes a finite number of steps to finish
21
Art of Multiprocessor Programming 21 Naïve Idea Consensus object stores reference to cell with current state Each thread creates new cell –computes outcome, –tries to switch pointer to its outcome Sadly, no … –consensus objects can be used once only
22
Art of Multiprocessor Programming 22 Naïve Idea enq deq
23
Art of Multiprocessor Programming 23 head Naïve Idea deq Concurrent Object enq ? Decide which to apply using consensus No good. Each thread can use consensus object only once
24
Art of Multiprocessor Programming 24 Once is not Enough? public decide(object value) { propose(value); Ball ball = this.queue.deq(); if (ball == Ball.RED) return proposed[i]; else return proposed[1-i]; } Solved one-shot 2-consensus. Not clear how to reuse or reread … Queue based consensus
25
Art of Multiprocessor Programming 25 Improved Idea: Linked-List Representation enq tail deq Each node contains a fresh consensus object used to decide on next operation
26
Art of Multiprocessor Programming 26 Universal Construction Object represented as –Initial Object State –A Log: a linked list of the method calls
27
Art of Multiprocessor Programming 27 Universal Construction Object represented as –Initial Object State –A Log: a linked list of the method calls New method call –Find end of list –Atomically append call –Compute response by replaying log
28
Art of Multiprocessor Programming 28 Basic Idea Use one-time consensus object to decide next pointer All threads update actual next pointer based on decision –OK because they all write the same value Challenges –Lock-free means we need to worry what happens if a thread stops in the middle
29
Art of Multiprocessor Programming 29 public class Node implements java.lang.Comparable { public Invoc invoc; public Consensus decideNext; public Node next; public int seq; public Node(Invoc invoc) { invoc = invoc; decideNext = new Consensus () seq = 0; } Basic Data Structures
30
Art of Multiprocessor Programming 30 public class Node implements java.lang.Comparable { public Invoc invoc; public Consensus decideNext; public Node next; public int seq; public Node(Invoc invoc) { invoc = invoc; decideNext = new Consensus () seq = 0; } Basic Data Structures Standard interface for class whose objects are totally ordered
31
Art of Multiprocessor Programming 31 public class Node implements java.lang.Comparable { public Invoc invoc; public Consensus decideNext; public Node next; public int seq; public Node(Invoc invoc) { invoc = invoc; decideNext = new Consensus () seq = 0; } Basic Data Structures the invocation
32
Art of Multiprocessor Programming 32 public class Node implements java.lang.Comparable { public Invoc invoc; public Consensus decideNext; public Node next; public int seq; public Node(Invoc invoc) { invoc = invoc; decideNext = new Consensus () seq = 0; } Basic Data Structures Decide on next node (next method applied to object)
33
Art of Multiprocessor Programming 33 public class Node implements java.lang.Comparable { public Invoc invoc; public Consensus decideNext; public Node next; public int seq; public Node(Invoc invoc) { invoc = invoc; decideNext = new Consensus () seq = 0; } Basic Data Structures Traversable pointer to next node (needed because you cannot repeatedly read a consensus object)
34
Art of Multiprocessor Programming 34 public class Node implements java.lang.Comparable { public Invoc invoc; public Consensus decideNext; public Node next; public int seq; public Node(Invoc invoc) { invoc = invoc; decideNext = new Consensus () seq = 0; } Basic Data Structures Seq number
35
Art of Multiprocessor Programming 35 public class Node implements java.lang.Comparable { public Invoc invoc; public Consensus decideNext; public Node next; public int seq; public Node(Invoc invoc) { invoc = invoc; decideNext = new Consensus () seq = 0; } Basic Data Structures Create new node for this method invocation
36
Art of Multiprocessor Programming 36 Universal Object head 123 decideNext (Consensus Object) Ptr to cell w/highest Seq Num Seq number, Invoc tail node next 4
37
Art of Multiprocessor Programming 37 Universal Object head 123 All threads repeatedly modify head…back to where we started? tail node 4
38
Art of Multiprocessor Programming 38 … The Solution head 123 tail node i 4 Make head an array Ptr to node at front Thread i updates location i Threads find head by finding Max of nodes pointed to by head array
39
Art of Multiprocessor Programming 39 Universal Object public class Universal { private Node[] head; private Node tail = new Node(); tail.seq = 1; for (int j=0; j < n; j++){ head[j] = tail }
40
Art of Multiprocessor Programming 40 Universal Object public class Universal { private Node[] head; private Node tail = new Node(); tail.seq = 1; for (int j=0; j < n; j++){ head[j] = tail } Head Pointers Array
41
Art of Multiprocessor Programming 41 Universal Object public class Universal { private Node[] head; private Node tail = new Node(); tail.seq = 1; for (int j=0; j < n; j++){ head[j] = tail } Tail is a sentinel node with sequence number 1
42
Art of Multiprocessor Programming 42 Universal Object public class Universal { private Node[] head; private Node tail = new Node(); tail.seq = 1; for (int j=0; j < n; j++){ head[j] = tail } Tail is a sentinel node with sequence number 1
43
Art of Multiprocessor Programming 43 Universal Object public class Universal { private Node[] head; private Node tail = new Node(); tail.seq = 1; for (int j=0; j < n; j++){ head[j] = tail } Initially head points to tail
44
Art of Multiprocessor Programming 44 public static Node max(Node[] array) { Node max = array[0]; for (int i = 1; i < array.length; i++) if (max.seq < array[i].seq) max = array[i]; return max; } Find Max Head Value
45
Art of Multiprocessor Programming 45 public static Node max(Node[] array) { Node max = array[0]; for (int i = 0; i < array.length; i++) if (max.seq < array[i].seq) max = array[i]; return max; } Find Max Head Value Traverse the array
46
Art of Multiprocessor Programming 46 public static Node max(Node[] array) { Node max = array[0]; for (int i = 0; i < array.length; i++) if (max.seq < array[i].seq) max = array[i]; return max; } Find Max Head Value Compare the seq nums of nodes pointed to by the array
47
Art of Multiprocessor Programming 47 public static Node max(Node[] array) { Node max = array[0]; for (int i = 0; i < array.length; i++) if (max.seq < array[i].seq) max = array[i]; return max; } Find Max Head Value Compare the seq nums of nodes pointed to by the array
48
Art of Multiprocessor Programming 48 Universal Application Part I public Response apply(Invoc invoc) { int i = ThreadID.get(); Node prefer = new node(invoc); while (prefer.seq == 0) { Node before = Node.max(head); Node after = before.decideNext.decide(prefer); before.next = after; after.seq = before.seq + 1; head[i] = after; } …
49
Art of Multiprocessor Programming 49 Universal Application Part I public Response apply(Invoc invoc) { int i = ThreadID.get(); Node prefer = new node(invoc); while (prefer.seq == 0) { Node before = Node.max(head); Node after = before.decideNext.decide(prefer); before.next = after; after.seq = before.seq + 1; head[i] = after; } … Apply will have invocation as input and return the appropriate response
50
Art of Multiprocessor Programming 50 Universal Application Part I public Response apply(Invoc invoc) { int i = ThreadID.get(); Node prefer = new node(invoc); while (prefer.seq == 0) { Node before = Node.max(head); Node after = before.decideNext.decide(prefer); before.next = after; after.seq = before.seq + 1; head[i] = after; } … My id
51
Art of Multiprocessor Programming 51 Universal Application Part I public Response apply(Invoc invoc) { int i = ThreadID.get(); Node prefer = new node(invoc); while (prefer.seq == 0) { Node before = Node.max(head); Node after = before.decideNext.decide(prefer); before.next = after; after.seq = before.seq + 1; head[i] = after; } … My method call
52
Art of Multiprocessor Programming 52 Universal Application Part I public Response apply(Invoc invoc) { int i = ThreadID.get(); Node prefer = new node(invoc); while (prefer.seq == 0) { Node before = Node.max(head); Node after = before.decideNext.decide(prefer); before.next = after; after.seq = before.seq + 1; head[i] = after; } … As long as I have not been threaded into list
53
Art of Multiprocessor Programming 53 Universal Application Part I public Response apply(Invoc invoc) { int i = ThreadID.get(); Node prefer = new node(invoc); while (prefer.seq == 0) { Node before = Node.max(head); Node after = before.decideNext.decide(prefer); before.next = after; after.seq = before.seq + 1; head[i] = after; } … Head of list to which we will try to append
54
Art of Multiprocessor Programming 54 Universal Application Part I public Response apply(Invoc invoc) { int i = ThreadID.get(); Node prefer = new node(invoc); while (prefer.seq == 0) { Node before = Node.max(head); Node after = before.decideNext.decide(prefer); before.next = after; after.seq = before.seq + 1; head[i] = after; } Propose next node
55
Art of Multiprocessor Programming 55 Universal Application public Response apply(Invoc invoc) { int i = ThreadID.get(); Node prefer = new node(invoc); while (prefer.seq == 0) { Node before = Node.max(head); Node after = before.decideNext.decide(prefer); before.next = after; after.seq = before.seq + 1; head[i] = after; } Set next field to consensus winner
56
Art of Multiprocessor Programming 56 Universal Application Part I public Response apply(Invoc invoc) { int i = ThreadID.get(); Node prefer = new node(invoc); while (prefer.seq == 0) { Node before = Node.max(head); Node after = before.decideNext.decide(prefer); before.next = after; after.seq = before.seq + 1; head[i] = after; } … Set seq number (indicating node was appended)
57
Art of Multiprocessor Programming 57 Universal Application Part I public Response apply(Invoc invoc) { int i = ThreadID.get(); Node prefer = new node(invoc); while (prefer.seq == 0) { Node before = Node.max(head); Node after = before.decideNext.decide(prefer); before.next = after; after.seq = before.seq + 1; head[i] = after; } … add to head array so new head will be found
58
Art of Multiprocessor Programming 58 Part 2 – Compute Response nullenq( ) tail Red’s method call … deq() enq( ) Return Private copy of object
59
Art of Multiprocessor Programming 59 Universal Application Part 2... //compute my response SeqObject MyObject = new SeqObject(); current = tail.next; while (current != prefer){ MyObject.apply(current.invoc); current = current.next; } return MyObject.apply(current.invoc); }
60
Art of Multiprocessor Programming 60 Universal Application Part II... //compute my response SeqObject MyObject = new SeqObject(); current = tail.next; while (current != prefer){ MyObject.apply(current.invoc); current = current.next; } return MyObject.apply(current.invoc); } Compute result by sequentially applying method calls in list to a private copy
61
Art of Multiprocessor Programming 61 Universal Application Part II... //compute my response SeqObject MyObject = new SeqObject(); current = tail.next; while (current != prefer){ MyObject.apply(current.invoc); current = current.next; } return MyObject.apply(current.invoc); } Start with copy of sequential object
62
Art of Multiprocessor Programming 62 Universal Application Part II... //compute my response SeqObject MyObject = new SeqObject(); current = tail.next; while (current != prefer){ MyObject.apply(current.invoc); current = current.next; } return MyObject.apply(current.invoc); } new method call appended after tail
63
Art of Multiprocessor Programming 63 Universal Application Part II... //compute my response SeqObject MyObject = new SeqObject(); current = tail.next; while (current != prefer){ MyObject.apply(current.invoc); current = current.next; } return MyObject.apply(current.invoc); } While my method call not linked …
64
Art of Multiprocessor Programming 64 Universal Application Part II... //compute my response SeqObject MyObject = new SeqObject(); current = tail.next; while (current != prefer){ MyObject.apply(current.invoc); current = current.next; } return MyObject.apply(current.invoc); } Apply current node’s method
65
Art of Multiprocessor Programming 65 Universal Application Part II... //compute my response SeqObject MyObject = new SeqObject(); current = tail.next; while (current != prefer){ MyObject.apply(current.invoc); current = current.next; } return MyObject.apply(current.invoc); } Return result after my method call applied
66
Art of Multiprocessor Programming 66 Correctness List defines linearized sequential history Thread returns its response based on list order
67
Art of Multiprocessor Programming 67 Lock-freedom Lock-free because –A thread moves forward in list –Can repeatedly fail to win consensus on “real” head only if another succeeds –Consensus winner adds node and completes within a finite number of steps
68
Art of Multiprocessor Programming 68 Wait-free Construction Lock-free construction + announce array Stores (pointer to) node in announce –If a thread doesn’t append its node –Another thread will see it in array and help append it
69
Art of Multiprocessor Programming 69 Helping “Announcing” my intention –Guarantees progress –Even if the scheduler hates me –My method call will complete Makes protocol wait-free Otherwise starvation possible
70
Art of Multiprocessor Programming 70 … … Wait-free Construction head 123 tail i 4 announce Ptr to cell thread i wants to append i
71
Art of Multiprocessor Programming 71 public class Universal { private Node[] announce; private Node[] head; private Node tail = new node(); tail.seq = 1; for (int j=0; j < n; j++){ head[j] = tail; announce[j] = tail }; The Announce Array
72
Art of Multiprocessor Programming 72 public class Universal { private Node[] announce; private Node[] head; private Node tail = new node(); tail.seq = 1; for (int j=0; j < n; j++){ head[j] = tail; announce[j] = tail }; The Announce Array Announce array
73
Art of Multiprocessor Programming 73 public class Universal { private Node[] announce; private Node[] head; private Node tail = new node(); tail.seq = 1; for (int j=0; j < n; j++){ head[j] = tail; announce[j] = tail }; The Announce Array All entries initially point to tail
74
Art of Multiprocessor Programming 74 public Response apply(Invoc invoc) { int i = ThreadID.get(); announce[i] = new Node(invoc); head[i] = Node.max(head); while (announce[i].seq == 0) { … // while node not appended to list … } A Cry For Help
75
Art of Multiprocessor Programming 75 public Response apply(Invoc invoc) { int i = ThreadID.get(); announce[i] = new Node(invoc); head[i] = Node.max(head); while (announce[i].seq == 0) { … // while node not appended to list … } A Cry For Help Announce new method call, asking help from others
76
Art of Multiprocessor Programming 76 public Response apply(Invoc invoc) { int i = ThreadID.get(); announce[i] = new Node(invoc); head[i] = Node.max(head); while (announce[i].seq == 0) { … // while node not appended to list … } A Cry For Help Look for end of list
77
Art of Multiprocessor Programming 77 public Response apply(Invoc invoc) { int i = ThreadID.get(); announce[i] = new Node(invoc); head[i] = Node.max(head); while (announce[i].seq == 0) { … // while node not appended to list … } A Cry For Help Main loop, while node not appended (either by me or helper)
78
Art of Multiprocessor Programming 78 Main Loop Non-zero sequence number indicates success Thread keeps helping append nodes Until its own node is appended
79
Art of Multiprocessor Programming 79 while (announce[i].seq == 0) { Node before = head[i]; Node help = announce[(before.seq + 1 % n)]; if (help.seq == 0) prefer = help; else prefer = announce[i]; … Main Loop
80
Art of Multiprocessor Programming 80 while (announce[i].seq == 0) { Node before = head[i]; Node help = announce[(before.seq + 1 % n)]; if (help.seq == 0) prefer = help; else prefer = announce[i]; … Main Loop Keep trying until my cell gets a sequence number
81
Art of Multiprocessor Programming 81 while (announce[i].seq == 0) { Node before = head[i]; Node help = announce[(before.seq + 1 % n)]; if (help.seq == 0) prefer = help; else prefer = announce[i]; … Main Loop Possible end of list
82
Art of Multiprocessor Programming 82 while (announce[i].seq == 0) { Node before = head[i]; Node help = announce[(before.seq + 1 % n)]; if (help.seq == 0) prefer = help; else prefer = announce[i]; … Main Loop Whom do I help?
83
Art of Multiprocessor Programming 83 Altruism Choose a thread to “help” If that thread needs help –Try to append its node –Otherwise append your own Worst case –Everyone tries to help same pitiful loser –Someone succeeds
84
Art of Multiprocessor Programming 84 Help! When last node in list has sequence number k All threads check … –Whether thread k+1 mod n wants help –If so, try to append her node first
85
Art of Multiprocessor Programming 85 Help! First time after thread k+1 announces –No guarantees After n more nodes appended –Everyone sees that thread k+1 wants help –Everyone tries to append that node –Someone succeeds
86
Art of Multiprocessor Programming 86 Sliding Window Lemma After thread A announces its node No more than n other calls –Can start and finish –Without appending A’s node
87
Art of Multiprocessor Programming 87 Helping head 1 2 3 Max head +1 = N+4 N+2 N+3 … announce Thread 4: Help me! 4 So all see and help append 4 tail
88
Art of Multiprocessor Programming 88 The Sliding Help Window head 1 2 3 N+2 N+3 … announce 4 tail Help 3 Help 4 3
89
Art of Multiprocessor Programming 89 while (announce[i].seq == 0) { Node before = head[i]; Node help = announce[(before.seq + 1 % n)]; if (help.seq == 0) prefer = help; else prefer = announce[i]; … Sliding Help Window In each main loop iteration pick another thread to help
90
Art of Multiprocessor Programming 90 while (announce[i].seq == 0) { Node before = head[i]; Node help = announce[(before.seq + 1 % n)]; if (help.seq == 0) prefer = help; else prefer = announce[i]; … Sliding Help Window Help if help required, but otherwise it’s all about me!
91
Art of Multiprocessor Programming 91 Rest is Same as Lock-free while (prefer.seq == 0) { … Node after = before.decideNext.decide(prefer); before.next = after; after.seq = before.seq + 1; head[i] = after; }
92
Art of Multiprocessor Programming 92 Rest is Same as Lock-free while (prefer.seq == 0) { … Node after = before.decideNext.decide(prefer); before.next = after; after.seq = before.seq + 1; head[i] = after; } Decide next node to be appended
93
Art of Multiprocessor Programming 93 Rest is Same as Lock-free while (prefer.seq == 0) { … Node after = before.decideNext.decide(prefer); before.next = after; after.seq = before.seq + 1; head[i] = after; } Update next based on decision
94
Art of Multiprocessor Programming 94 Rest is Same as Lock-free while (prefer.seq == 0) { … Node after = before.decideNext.decide(prefer); before.next = after; after.seq = before.seq + 1; head[i] = after; } Tell world that node is appended
95
Art of Multiprocessor Programming 95 Finishing the Job Once thread’s node is linked The rest is again the same as in lock- free alg Compute the result by sequentially applying the method calls in the list to a private copy of the object starting from the initial state
96
Art of Multiprocessor Programming 96 Then Same Part II... //compute my response SeqObject MyObject = new SeqObject(); current = tail.next; while (current != prefer){ MyObject.apply(current.invoc); current = current.next; } return MyObject.apply(current.invoc); }
97
Art of Multiprocessor Programming 97 Universal Application Part II... //compute my response SeqObject MyObject = new SeqObject(); current = tail.next; while (current != prefer){ MyObject.apply(current.invoc); current = current.next; } return MyObject.apply(current.invoc); } Return result after applying my method
98
Art of Multiprocessor Programming 98 Shared-Memory Computability Wait-free/Lock-free computable = Solving n-consensus 10011 Universal Object
99
Art of Multiprocessor Programming 99 On Older Architectures IBM 360 –testAndSet (getAndSet) NYU UltraComputer –getAndAdd Neither universal –Except for 2 threads
100
Art of Multiprocessor Programming 100 On Newer Architectures Intel x86, Itanium, SPARC –compareAndSet Alpha AXP, PowerPC –Load-locked/store-conditional All universal –For any number of threads Trend is clear …
101
Art of Multiprocessor Programming 101 Practical Implications Any architecture that does not provide a universal primitive has inherent limitations You cannot avoid locking for concurrent data structures …
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.