Presentation is loading. Please wait.

Presentation is loading. Please wait.

Linked Lists: Locking, Lock-Free, and Beyond …

Similar presentations


Presentation on theme: "Linked Lists: Locking, Lock-Free, and Beyond …"— Presentation transcript:

1 Linked Lists: Locking, Lock-Free, and Beyond …
Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

2 Last Lecture: Spin-Locks
. CS spin lock critical section Resets lock upon exit Art of Multiprocessor Programming

3 Today: Concurrent Objects
Adding threads should not lower throughput Contention effects Mostly fixed by Queue locks Art of Multiprocessor Programming

4 Today: Concurrent Objects
Adding threads should not lower throughput Contention effects Mostly fixed by Queue locks Should increase throughput Not possible if inherently sequential Surprising things are parallelizable Art of Multiprocessor Programming 4 4

5 Coarse-Grained Synchronization
Each method locks the object Avoid contention using queue locks Art of Multiprocessor Programming

6 Coarse-Grained Synchronization
Each method locks the object Avoid contention using queue locks Easy to reason about In simple cases Art of Multiprocessor Programming 6 6

7 Coarse-Grained Synchronization
Each method locks the object Avoid contention using queue locks Easy to reason about In simple cases So, are we done? Art of Multiprocessor Programming 7 7

8 Coarse-Grained Synchronization
Sequential bottleneck Threads “stand in line” Art of Multiprocessor Programming

9 Coarse-Grained Synchronization
Sequential bottleneck Threads “stand in line” Adding more threads Does not improve throughput Struggle to keep it from getting worse Art of Multiprocessor Programming 9 9

10 Coarse-Grained Synchronization
Sequential bottleneck Threads “stand in line” Adding more threads Does not improve throughput Struggle to keep it from getting worse So why even use a multiprocessor? Well, some apps inherently parallel … Art of Multiprocessor Programming 10 10

11 Art of Multiprocessor Programming
This Lecture Introduce four “patterns” Bag of tricks … Methods that work more than once … Art of Multiprocessor Programming

12 Art of Multiprocessor Programming
This Lecture Introduce four “patterns” Bag of tricks … Methods that work more than once … For highly-concurrent objects Concurrent access More threads, more throughput Art of Multiprocessor Programming 12 12

13 First: Fine-Grained Synchronization
Instead of using a single lock … Art of Multiprocessor Programming

14 First: Fine-Grained Synchronization
Instead of using a single lock … Split object into Independently-synchronized components Art of Multiprocessor Programming

15 First: Fine-Grained Synchronization
Instead of using a single lock … Split object into Independently-synchronized components Methods conflict when they access The same component … At the same time Art of Multiprocessor Programming

16 Second: Optimistic Synchronization
Search without locking … Art of Multiprocessor Programming

17 Second: Optimistic Synchronization
Search without locking … If you find it, lock and check … OK: we are done Oops: start over Art of Multiprocessor Programming

18 Second: Optimistic Synchronization
Search without locking … If you find it, lock and check … OK: we are done Oops: start over Evaluation Usually cheaper than locking, but Mistakes are expensive Art of Multiprocessor Programming

19 Third: Lazy Synchronization
Postpone hard work Art of Multiprocessor Programming

20 Third: Lazy Synchronization
Postpone hard work Removing components is tricky Art of Multiprocessor Programming

21 Third: Lazy Synchronization
Postpone hard work Removing components is tricky Logical removal Mark component to be deleted Art of Multiprocessor Programming

22 Third: Lazy Synchronization
Postpone hard work Removing components is tricky Logical removal Mark component to be deleted Physical removal Do what needs to be done Art of Multiprocessor Programming

23 Fourth: Lock-Free Synchronization
Don’t use locks at all Use compareAndSet() & relatives … Art of Multiprocessor Programming

24 Fourth: Lock-Free Synchronization
Don’t use locks at all Use compareAndSet() & relatives … Advantages No Scheduler Assumptions/Support Art of Multiprocessor Programming

25 Fourth: Lock-Free Synchronization
Don’t use locks at all Use compareAndSet() & relatives … Advantages No Scheduler Assumptions/Support Disadvantages Complex Sometimes high overhead Art of Multiprocessor Programming

26 Art of Multiprocessor Programming
Linked List Illustrate these patterns … Using a list-based Set Common application Building block for other apps Art of Multiprocessor Programming

27 Art of Multiprocessor Programming
Set Interface Unordered collection of items Art of Multiprocessor Programming

28 Art of Multiprocessor Programming
Set Interface Unordered collection of items No duplicates Art of Multiprocessor Programming

29 Art of Multiprocessor Programming
Set Interface Unordered collection of items No duplicates Methods add(x) put x in set remove(x) take x out of set contains(x) tests if x in set Art of Multiprocessor Programming

30 Art of Multiprocessor Programming
List-Based Sets public interface Set<T> { public boolean add(T x); public boolean remove(T x); public boolean contains(T x); } Art of Multiprocessor Programming

31 Art of Multiprocessor Programming
List-Based Sets public interface Set<T> { public boolean add(T x); public boolean remove(T x); public boolean contains(T x); } Add item to set Art of Multiprocessor Programming

32 Art of Multiprocessor Programming
List-Based Sets public interface Set<T> { public boolean add(T x); public boolean remove(T x); public boolean contains(Tt x); } Remove item from set Art of Multiprocessor Programming

33 Art of Multiprocessor Programming
List-Based Sets public interface Set<T> { public boolean add(T x); public boolean remove(T x); public boolean contains(T x); } Is item in set? Art of Multiprocessor Programming

34 Art of Multiprocessor Programming
List Node public class Node { public T item; public int key; public volatile Node next; } Art of Multiprocessor Programming

35 Art of Multiprocessor Programming
List Node public class Node { public T item; public int key; public volatile Node next; } item of interest Art of Multiprocessor Programming

36 Art of Multiprocessor Programming
List Node public class Node { public T item; public int key; public volatile Node next; } Usually hash code Art of Multiprocessor Programming

37 Art of Multiprocessor Programming
List Node public class Node { public T item; public int key; public volatile Node next; } Reference to next node Art of Multiprocessor Programming

38 The List-Based Set Sorted with Sentinel nodes
-∞ a b c +∞ Sorted with Sentinel nodes (min & max possible keys) Art of Multiprocessor Programming

39 Reasoning about Concurrent Objects
Invariant Property that always holds Art of Multiprocessor Programming

40 Reasoning about Concurrent Objects
Invariant Property that always holds Established because True when object is created Truth preserved by each method Each step of each method Art of Multiprocessor Programming

41 Art of Multiprocessor Programming
Specifically … Invariants preserved by add() remove() contains() Art of Multiprocessor Programming

42 Art of Multiprocessor Programming
Specifically … Invariants preserved by add() remove() contains() Most steps are trivial Usually one step tricky Often linearization point Art of Multiprocessor Programming

43 Art of Multiprocessor Programming
Interference Invariants make sense only if methods considered are the only modifiers Art of Multiprocessor Programming

44 Art of Multiprocessor Programming
Interference Invariants make sense only if methods considered are the only modifiers Language encapsulation helps List nodes not visible outside class Art of Multiprocessor Programming 44 44

45 Art of Multiprocessor Programming
Interference Invariants make sense only if methods considered are the only modifiers Language encapsulation helps List nodes not visible outside class Art of Multiprocessor Programming 45 45

46 Art of Multiprocessor Programming
Interference Freedom from interference needed even for removed nodes Some algorithms traverse removed nodes Careful with malloc()& free()! We rely on garbage collection Art of Multiprocessor Programming

47 Art of Multiprocessor Programming
Abstract Data Types Concrete representation: Abstract Type: {a, b} a b Art of Multiprocessor Programming

48 Art of Multiprocessor Programming
Abstract Data Types Meaning of rep given by abstraction map S( ) = {a,b} a b Art of Multiprocessor Programming

49 Art of Multiprocessor Programming
Rep Invariant Which concrete values meaningful? Sorted? Duplicates? Rep invariant Characterizes legal concrete reps Preserved by methods Relied on by methods Art of Multiprocessor Programming

50 Art of Multiprocessor Programming
Blame Game Rep invariant is a contract Suppose add()leaves behind 2 copies of x remove() removes only 1 Which is incorrect? Art of Multiprocessor Programming

51 Art of Multiprocessor Programming
Blame Game Suppose add() leaves behind 2 copies of x remove() removes only 1 Art of Multiprocessor Programming

52 Art of Multiprocessor Programming
Blame Game Suppose add() leaves behind 2 copies of x remove() removes only 1 Which is incorrect? If rep invariant says no duplicates add() is incorrect Otherwise remove() is incorrect Art of Multiprocessor Programming

53 Rep Invariant (partly)
Sentinel nodes tail reachable from head Sorted No duplicates Art of Multiprocessor Programming

54 Art of Multiprocessor Programming
Abstraction Map S(head) = { x | there exists a such that a reachable from head and a.item = x } Art of Multiprocessor Programming

55 Sequential List Based Set
add() a c d remove() a b c Art of Multiprocessor Programming

56 Sequential List Based Set
add() a c d b remove() a b c Art of Multiprocessor Programming

57 Coarse-Grained Locking
b d Art of Multiprocessor Programming

58 Coarse-Grained Locking
b d c Art of Multiprocessor Programming

59 Coarse-Grained Locking
b d honk! honk! c Simple but hotspot + bottleneck Art of Multiprocessor Programming

60 Coarse-Grained Locking
Easy, same as synchronized methods “One lock to rule them all …” Art of Multiprocessor Programming

61 Coarse-Grained Locking
Easy, same as synchronized methods “One lock to rule them all …” Simple, clearly correct Deserves respect! Works poorly with contention Queue locks help But bottleneck still an issue Art of Multiprocessor Programming 61 61

62 Art of Multiprocessor Programming
Fine-grained Locking Requires careful thought “Do not meddle in the affairs of wizards, for they are subtle and quick to anger” We can improve concurrency by locking individual entries, rather than locking the list as a whole. Instead of placing a lock on the entire list, let us add a lock to each entry, along with lock() and unlock() methods. As a thread traverses the list, it locks each entry when it first visits, and sometime later releases it. Suchfine-grained locking permits concurrent threads to traverse the list together in a pipelined fashion. Art of Multiprocessor Programming

63 Art of Multiprocessor Programming
Fine-grained Locking Requires careful thought “Do not meddle in the affairs of wizards, for they are subtle and quick to anger” Split object into pieces Each piece has own lock Methods that work on disjoint pieces need not exclude each other We can improve concurrency by locking individual entries, rather than locking the list as a whole. Instead of placing a lock on the entire list, let us add a lock to each entry, along with lock() and unlock() methods. As a thread traverses the list, it locks each entry when it first visits, and sometime later releases it. Suchfine-grained locking permits concurrent threads to traverse the list together in a pipelined fashion. Art of Multiprocessor Programming 63 63

64 Hand-over-Hand locking
b c Art of Multiprocessor Programming

65 Hand-over-Hand locking
b c Art of Multiprocessor Programming

66 Hand-over-Hand locking
b c Art of Multiprocessor Programming

67 Hand-over-Hand locking
b c Art of Multiprocessor Programming

68 Hand-over-Hand locking
b c Art of Multiprocessor Programming

69 Art of Multiprocessor Programming
Removing a Node a b c d remove(b) Art of Multiprocessor Programming

70 Art of Multiprocessor Programming
Removing a Node a b c d remove(b) Art of Multiprocessor Programming

71 Art of Multiprocessor Programming
Removing a Node a b c d remove(b) Art of Multiprocessor Programming

72 Art of Multiprocessor Programming
Removing a Node a b c d remove(b) Art of Multiprocessor Programming 72 72

73 Art of Multiprocessor Programming
Removing a Node a b c d remove(b) Here is a naive approach to removing a node. Each thread locks the node being examined and its predecessor. Art of Multiprocessor Programming

74 Art of Multiprocessor Programming
Removing a Node a c d Why lock victim node? remove(b) Here is a naive approach to removing a node. Each thread locks the node being examined and its predecessor. Art of Multiprocessor Programming

75 Art of Multiprocessor Programming
Concurrent Removes a b c d remove(c) remove(b) Supposed we only locked one node and not two. Consider two concurrent threads that want to remove adjacent nodes. Art of Multiprocessor Programming

76 Art of Multiprocessor Programming
Concurrent Removes a b c d remove(c) remove(b) The red thread looks for the predecessor to c, while the green thread looks for the predecessor to b. Art of Multiprocessor Programming

77 Art of Multiprocessor Programming
Concurrent Removes a b c d remove(c) remove(b) Art of Multiprocessor Programming

78 Art of Multiprocessor Programming
Concurrent Removes a b c d remove(c) remove(b) Art of Multiprocessor Programming

79 Art of Multiprocessor Programming
Concurrent Removes a b c d remove(c) remove(b) Art of Multiprocessor Programming

80 Art of Multiprocessor Programming
Concurrent Removes a b c d remove(c) remove(b) Art of Multiprocessor Programming

81 Art of Multiprocessor Programming
Concurrent Removes a b c d remove(c) remove(b) Art of Multiprocessor Programming

82 Art of Multiprocessor Programming
Concurrent Removes a b c d remove(c) remove(b) Art of Multiprocessor Programming

83 Art of Multiprocessor Programming
Concurrent Removes a b c d remove(c) remove(b) Art of Multiprocessor Programming 83 83

84 Art of Multiprocessor Programming
Concurrent Removes a b c d remove(c) remove(b) Art of Multiprocessor Programming 84 84

85 Art of Multiprocessor Programming
Uh, Oh a c d remove(c) remove(b) But the final effect is to remove b but not c! Art of Multiprocessor Programming

86 Art of Multiprocessor Programming
Uh, Oh Bad news, c not removed a c d remove(c) remove(b) But the final effect is to remove b but not c! Art of Multiprocessor Programming

87 Art of Multiprocessor Programming
Problem To delete node c Swing node b’s next field to d Problem is, Someone deleting b concurrently could direct a pointer to c a b c a b c Art of Multiprocessor Programming

88 Art of Multiprocessor Programming
Insight If a node is locked No one can delete node’s successor If a thread locks Node to be deleted And its predecessor Then it works Art of Multiprocessor Programming

89 Art of Multiprocessor Programming
Hand-Over-Hand Again a b c d remove(b) Art of Multiprocessor Programming

90 Art of Multiprocessor Programming
Hand-Over-Hand Again a b c d remove(b) Art of Multiprocessor Programming

91 Art of Multiprocessor Programming
Hand-Over-Hand Again a b c d remove(b) Art of Multiprocessor Programming

92 Art of Multiprocessor Programming
Hand-Over-Hand Again a b c d remove(b) Found it! Art of Multiprocessor Programming

93 Art of Multiprocessor Programming
Hand-Over-Hand Again a b c d remove(b) Found it! Art of Multiprocessor Programming

94 Art of Multiprocessor Programming
Hand-Over-Hand Again a c d remove(b) Art of Multiprocessor Programming

95 Art of Multiprocessor Programming
Removing a Node a b c d remove(c) remove(b) Art of Multiprocessor Programming

96 Art of Multiprocessor Programming
Removing a Node a b c d remove(c) remove(b) Art of Multiprocessor Programming

97 Art of Multiprocessor Programming
Removing a Node a b c d remove(c) remove(b) Art of Multiprocessor Programming

98 Art of Multiprocessor Programming
Removing a Node a b c d remove(c) remove(b) Art of Multiprocessor Programming

99 Art of Multiprocessor Programming
Removing a Node a b c d remove(c) remove(b) Art of Multiprocessor Programming

100 Art of Multiprocessor Programming
Removing a Node a b c d remove(c) remove(b) Art of Multiprocessor Programming

101 Art of Multiprocessor Programming
Removing a Node a b c d remove(c) remove(b) Art of Multiprocessor Programming

102 Art of Multiprocessor Programming
Removing a Node a b c d remove(c) remove(b) Art of Multiprocessor Programming

103 Art of Multiprocessor Programming
Removing a Node a b c d remove(c) Must acquire Lock for b Art of Multiprocessor Programming

104 Waiting to acquire lock for b
Removing a Node a b c d remove(c) Waiting to acquire lock for b Art of Multiprocessor Programming

105 Art of Multiprocessor Programming
Removing a Node a b c d remove(c) Wait! Art of Multiprocessor Programming

106 Art of Multiprocessor Programming
Removing a Node a b d Proceed to remove(b) Art of Multiprocessor Programming

107 Art of Multiprocessor Programming
Removing a Node a b d remove(b) Art of Multiprocessor Programming

108 Art of Multiprocessor Programming
Removing a Node a b d remove(b) Art of Multiprocessor Programming

109 Art of Multiprocessor Programming
Removing a Node a d remove(b) Art of Multiprocessor Programming

110 Art of Multiprocessor Programming
Removing a Node a d Art of Multiprocessor Programming

111 Art of Multiprocessor Programming
Remove method public boolean remove(T item) { int key = item.hashCode(); Node pred, curr; try { } finally { curr.unlock(); pred.unlock(); }} Art of Multiprocessor Programming

112 Art of Multiprocessor Programming
Remove method public boolean remove(T item) { int key = item.hashCode(); Node pred, curr; try { } finally { curr.unlock(); pred.unlock(); }} Key used to order node Art of Multiprocessor Programming

113 Predecessor and current nodes
Remove method public boolean remove(T item) { int key = item.hashCode(); Node pred, curr; try { } finally { currNode.unlock(); predNode.unlock(); }} Predecessor and current nodes Art of Multiprocessor Programming

114 Make sure locks released
Remove method public boolean remove(T item) { int key = item.hashCode(); Node pred, curr; try { } finally { curr.unlock(); pred.unlock(); }} Make sure locks released Art of Multiprocessor Programming

115 Art of Multiprocessor Programming
Remove method public boolean remove(T item) { int key = item.hashCode(); Node pred, curr; try { } finally { curr.unlock(); pred.unlock(); }} Everything else Art of Multiprocessor Programming

116 Art of Multiprocessor Programming
Remove method try { pred = head; pred.lock(); curr = pred.next; curr.lock(); } finally { … } Art of Multiprocessor Programming

117 Art of Multiprocessor Programming
Remove method lock pred == head try { pred = head; pred.lock(); curr = pred.next; curr.lock(); } finally { … } Art of Multiprocessor Programming

118 Art of Multiprocessor Programming
Remove method try { pred = head; pred.lock(); curr = pred.next; curr.lock(); } finally { … } Lock current Art of Multiprocessor Programming

119 Art of Multiprocessor Programming
Remove method try { pred = head; pred.lock(); curr = pred.next; curr.lock(); } finally { … } Traversing list Art of Multiprocessor Programming

120 Art of Multiprocessor Programming
Remove: searching while (curr.key <= key) { if (item == curr.item) { pred.next = curr.next; return true; } pred.unlock(); pred = curr; curr = curr.next; curr.lock(); return false; Art of Multiprocessor Programming

121 Art of Multiprocessor Programming
Remove: searching while (curr.key <= key) { if (item == curr.item) { pred.next = curr.next; return true; } pred.unlock(); pred = curr; curr = curr.next; curr.lock(); return false; Search key range Art of Multiprocessor Programming

122 At start of each loop: curr and pred locked
Remove: searching while (curr.key <= key) { if (item == curr.item) { pred.next = curr.next; return true; } pred.unlock(); pred = curr; curr = curr.next; curr.lock(); return false; At start of each loop: curr and pred locked Art of Multiprocessor Programming

123 If item found, remove node
Remove: searching while (curr.key <= key) { if (item == curr.item) { pred.next = curr.next; return true; } pred.unlock(); pred = curr; curr = curr.next; curr.lock(); return false; If item found, remove node Art of Multiprocessor Programming

124 Art of Multiprocessor Programming
Remove: searching Unlock predecessor while (curr.key <= key) { if (item == curr.item) { pred.next = curr.next; return true; } pred.unlock(); pred = curr; curr = curr.next; curr.lock(); return false; Art of Multiprocessor Programming

125 Art of Multiprocessor Programming
Remove: searching Only one node locked! while (curr.key <= key) { if (item == curr.item) { pred.next = curr.next; return true; } pred.unlock(); pred = curr; curr = curr.next; curr.lock(); return false; Art of Multiprocessor Programming

126 Art of Multiprocessor Programming
Remove: searching while (curr.key <= key) { if (item == curr.item) { pred.next = curr.next; return true; } pred.unlock(); pred = curr; curr = curr.next; curr.lock(); return false; demote current Art of Multiprocessor Programming

127 Find and lock new current
Remove: searching while (curr.key <= key) { if (item == curr.item) { pred.next = curr.next; return true; } pred.unlock(); pred = currNode; curr = curr.next; curr.lock(); return false; Find and lock new current Art of Multiprocessor Programming

128 Lock invariant restored
Remove: searching while (curr.key <= key) { if (item == curr.item) { pred.next = curr.next; return true; } pred.unlock(); pred = currNode; curr = curr.next; curr.lock(); return false; Lock invariant restored Art of Multiprocessor Programming

129 Art of Multiprocessor Programming
Remove: searching while (curr.key <= key) { if (item == curr.item) { pred.next = curr.next; return true; } pred.unlock(); pred = curr; curr = curr.next; curr.lock(); return false; Otherwise, not present Art of Multiprocessor Programming

130 Why remove() is linearizable
while (curr.key <= key) { if (item == curr.item) { pred.next = curr.next; return true; } pred.unlock(); pred = curr; curr = curr.next; curr.lock(); return false; pred reachable from head curr is pred.next So curr.item is in the set Art of Multiprocessor Programming

131 Why remove() is linearizable
while (curr.key <= key) { if (item == curr.item) { pred.next = curr.next; return true; } pred.unlock(); pred = curr; curr = curr.next; curr.lock(); return false; Linearization point if item is present Art of Multiprocessor Programming

132 Why remove() is linearizable
while (curr.key <= key) { if (item == curr.item) { pred.next = curr.next; return true; } pred.unlock(); pred = curr; curr = curr.next; curr.lock(); return false; Node locked, so no other thread can remove it …. Art of Multiprocessor Programming

133 Why remove() is linearizable
while (curr.key <= key) { if (item == curr.item) { pred.next = curr.next; return true; } pred.unlock(); pred = curr; curr = curr.next; curr.lock(); return false; Item not present Art of Multiprocessor Programming

134 Why remove() is linearizable
while (curr.key <= key) { if (item == curr.item) { pred.next = curr.next; return true; } pred.unlock(); pred = curr; curr = curr.next; curr.lock(); return false; pred reachable from head curr is pred.next pred.key < key key < curr.key Art of Multiprocessor Programming

135 Why remove() is linearizable
while (curr.key <= key) { if (item == curr.item) { pred.next = curr.next; return true; } pred.unlock(); pred = curr; curr = curr.next; curr.lock(); return false; Linearization point Notice that we could also have the linearization points be those when the locks are acquired. Art of Multiprocessor Programming

136 Art of Multiprocessor Programming
Adding Nodes To add node e Must lock predecessor Must lock successor Neither can be deleted (Is successor lock actually required?) successor lock not actually required! Art of Multiprocessor Programming

137 Art of Multiprocessor Programming
Same Abstraction Map S(head) = { x | there exists a such that a reachable from head and a.item = x } Art of Multiprocessor Programming

138 Art of Multiprocessor Programming
Rep Invariant Easy to check that tail always reachable from head Nodes sorted, no duplicates Art of Multiprocessor Programming

139 Art of Multiprocessor Programming
Drawbacks Better than coarse-grained lock Threads can traverse in parallel Still not ideal Long chain of acquire/release Inefficient Art of Multiprocessor Programming

140 Optimistic Synchronization
Find nodes without locking Lock nodes Check that everything is OK Art of Multiprocessor Programming

141 Optimistic: Traverse without Locking
b d e Aha! add(c) Art of Multiprocessor Programming

142 Optimistic: Lock and Load
b d e add(c) Art of Multiprocessor Programming

143 Optimistic: Lock and Load
b d e add(c) Art of Multiprocessor Programming 145 145

144 Art of Multiprocessor Programming
What could go wrong? a b d e Aha! add(c) Art of Multiprocessor Programming

145 Art of Multiprocessor Programming
What could go wrong? a b d e add(c) Art of Multiprocessor Programming 147 147

146 Art of Multiprocessor Programming
What could go wrong? a b d e remove(b) Art of Multiprocessor Programming 148 148

147 Art of Multiprocessor Programming
What could go wrong? a b d e remove(b) Art of Multiprocessor Programming 149 149

148 Art of Multiprocessor Programming
What could go wrong? a b d e add(c) Art of Multiprocessor Programming 150 150

149 Art of Multiprocessor Programming
What could go wrong? c a b d e add(c) Art of Multiprocessor Programming 151 151

150 Art of Multiprocessor Programming
What could go wrong? a d e add(c) Uh-oh Art of Multiprocessor Programming 152 152

151 Yes, b still reachable from head
Validate – Part 1 a b d e Yes, b still reachable from head add(c) Art of Multiprocessor Programming

152 What Else Could Go Wrong?
b d e Aha! add(c) Art of Multiprocessor Programming 154 154

153 What Else Coould Go Wrong?
b d e add(b’) add(c) Art of Multiprocessor Programming

154 What Else Coould Go Wrong?
b d e add(b’) b’ add(c) Art of Multiprocessor Programming 156 156

155 What Else Could Go Wrong?
b d e b’ add(c) Art of Multiprocessor Programming 157 157

156 What Else Could Go Wrong?
b d e add(c) Art of Multiprocessor Programming 158 158

157 Validate Part 2 (while holding locks)
b d e Yes, b still points to d add(c) Art of Multiprocessor Programming

158 Optimistic: Linearization Point
b d e c add(c) Art of Multiprocessor Programming

159 Art of Multiprocessor Programming
Same Abstraction Map S(head) = { x | there exists a such that a reachable from head and a.item = x } Art of Multiprocessor Programming

160 Art of Multiprocessor Programming
Invariants Careful: we may traverse deleted nodes But we establish properties by Validation After we lock target nodes Art of Multiprocessor Programming

161 Art of Multiprocessor Programming
Correctness If Nodes b and c both locked Node b still accessible Node c still successor to b Then Neither will be deleted OK to delete and return true Art of Multiprocessor Programming

162 Art of Multiprocessor Programming
Unsuccessful Remove a b d e Aha! remove(c) Art of Multiprocessor Programming

163 Yes, b still reachable from head
Validate (1) a b d e Yes, b still reachable from head remove(c) Art of Multiprocessor Programming

164 Art of Multiprocessor Programming
Validate (2) a b d e Yes, b still points to d remove(c) Art of Multiprocessor Programming

165 Art of Multiprocessor Programming
OK Computer a b d e remove(c) return false Art of Multiprocessor Programming

166 Art of Multiprocessor Programming
Correctness If Nodes b and d both locked Node b still accessible Node d still successor to b Then Neither will be deleted No thread can add c after b OK to return false Art of Multiprocessor Programming

167 Art of Multiprocessor Programming
Validation private boolean validate(Node pred, Node curry) { Node node = head; while (node.key <= pred.key) { if (node == pred) return pred.next == curr; node = node.next; } return false; Art of Multiprocessor Programming

168 Predecessor & current nodes
Validation private boolean validate(Node pred, Node curr) { Node node = head; while (node.key <= pred.key) { if (node == pred) return pred.next == curr; node = node.next; } return false; Predecessor & current nodes Art of Multiprocessor Programming

169 Art of Multiprocessor Programming
Validation private boolean validate(Node pred, Node curr) { Node node = head; while (node.key <= pred.key) { if (node == pred) return pred.next == curr; node = node.next; } return false; Begin at the beginning Art of Multiprocessor Programming

170 Art of Multiprocessor Programming
Validation private boolean validate(Node pred, Node curr) { Node node = head; while (node.key <= pred.key) { if (node == pred) return pred.next == curr; node = node.next; } return false; Search range of keys Art of Multiprocessor Programming

171 Predecessor reachable
Validation private boolean validate(Node pred, Node curr) { Node node = head; while (node.key <= pred.key) { if (node == pred) return pred.next == curr; node = node.next; } return false; Predecessor reachable Art of Multiprocessor Programming

172 Art of Multiprocessor Programming
Validation private boolean validate(Node pred, Node curr) { Node node = head; while (node.key <= pred.key) { if (node == pred) return pred.next == curr; node = node.next; } return false; Is current node next? Art of Multiprocessor Programming

173 Art of Multiprocessor Programming
Validation private boolean validate(Node pred, Node curr) { Node node = head; while (node.key <= pred.key) { if (node == pred) return pred.next == curr; node = node.next; } return false; Otherwise move on Art of Multiprocessor Programming

174 Predecessor not reachable
Validation Predecessor not reachable private boolean validate(Node pred, Node curr) { Node node = head; while (node.key <= pred.key) { if (node == pred) return pred.next == curr; node = node.next; } return false; Art of Multiprocessor Programming

175 Art of Multiprocessor Programming
Remove: searching public boolean remove(T item) { int key = item.hashCode(); retry: while (true) { Node pred = head; Node curr = pred.next; while (curr.key <= key) { if (item == curr.item) break; pred = curr; curr = curr.next; } … Art of Multiprocessor Programming

176 Art of Multiprocessor Programming
Remove: searching public boolean remove(T item) { int key = item.hashCode(); retry: while (true) { Node pred = head; Node curr = pred.next; while (curr.key <= key) { if (item == curr.item) break; pred = curr; curr = curr.next; } … Search key Art of Multiprocessor Programming

177 Retry on synchronization conflict
Remove: searching public boolean remove(T item) { int key = item.hashCode(); retry: while (true) { Node pred = head; Node curr = pred.next; while (curr.key <= key) { if (item == curr.item) break; pred = curr; curr = curr.next; } … Retry on synchronization conflict Art of Multiprocessor Programming

178 Examine predecessor and current nodes
Remove: searching public boolean remove(T item) { int key = item.hashCode(); retry: while (true) { Node pred = head; Node curr = pred.next; while (curr.key <= key) { if (item == curr.item) break; pred = curr; curr = curr.next; } … Examine predecessor and current nodes Art of Multiprocessor Programming

179 Art of Multiprocessor Programming
Remove: searching public boolean remove(T item) { int key = item.hashCode(); retry: while (true) { Node pred = head; Node curr = pred.next; while (curr.key <= key) { if (item == curr.item) break; pred = curr; curr = curr.next; } … Search by key Art of Multiprocessor Programming

180 Art of Multiprocessor Programming
Remove: searching public boolean remove(T item) { int key = item.hashCode(); retry: while (true) { Node pred = head; Node curr = pred.next; while (curr.key <= key) { if (item == curr.item) break; pred = curr; curr = curr.next; } … Stop if we find item Art of Multiprocessor Programming

181 Art of Multiprocessor Programming
Remove: searching public boolean remove(T item) { int key = item.hashCode(); retry: while (true) { Node pred = head; Node curr = pred.next; while (curr.key <= key) { if (item == curr.item) break; pred = curr; curr = curr.next; } … Move along Art of Multiprocessor Programming

182 Art of Multiprocessor Programming
On Exit from Loop If item is present curr holds item pred just before curr If item is absent curr has first higher key Assuming no synchronization problems Art of Multiprocessor Programming

183 Art of Multiprocessor Programming
Remove Method try { pred.lock(); curr.lock(); if (validate(pred,curr) { if (curr.item == item) { pred.next = curr.next; return true; } else { return false; }}} finally { pred.unlock(); curr.unlock(); }}} Art of Multiprocessor Programming

184 Art of Multiprocessor Programming
Remove Method try { pred.lock(); curr.lock(); if (validate(pred,curr) { if (curr.item == item) { pred.next = curr.next; return true; } else { return false; }}} finally { pred.unlock(); curr.unlock(); }}} Always unlock Art of Multiprocessor Programming

185 Art of Multiprocessor Programming
Remove Method try { pred.lock(); curr.lock(); if (validate(pred,curr) { if (curr.item == item) { pred.next = curr.next; return true; } else { return false; }}} finally { pred.unlock(); curr.unlock(); }}} Lock both nodes Art of Multiprocessor Programming

186 Check for synchronization conflicts
Remove Method try { pred.lock(); curr.lock(); if (validate(pred,curr) { if (curr.item == item) { pred.next = curr.next; return true; } else { return false; }}} finally { pred.unlock(); curr.unlock(); }}} Check for synchronization conflicts Art of Multiprocessor Programming

187 target found, remove node
Remove Method try { pred.lock(); curr.lock(); if (validate(pred,curr) { if (curr.item == item) { pred.next = curr.next; return true; } else { return false; }}} finally { pred.unlock(); curr.unlock(); }}} target found, remove node Art of Multiprocessor Programming

188 Art of Multiprocessor Programming
Remove Method try { pred.lock(); curr.lock(); if (validate(pred,curr) { if (curr.item == item) { pred.next = curr.next; return true; } else { return false; }}} finally { pred.unlock(); curr.unlock(); }}} target not found Art of Multiprocessor Programming

189 Art of Multiprocessor Programming
Optimistic List Limited hot-spots Targets of add(), remove(), contains() No contention on traversals Moreover Traversals are wait-free Food for thought … Art of Multiprocessor Programming

190 Art of Multiprocessor Programming
So Far, So Good Much less lock acquisition/release Performance Concurrency Problems Need to traverse list twice contains() method acquires locks Art of Multiprocessor Programming

191 Art of Multiprocessor Programming
Evaluation Optimistic is effective if cost of scanning twice without locks is less than cost of scanning once with locks Drawback contains() acquires locks 90% of calls in many apps Art of Multiprocessor Programming

192 Art of Multiprocessor Programming
Lazy List Like optimistic, except Scan once contains(x) never locks … Key insight Removing nodes causes trouble Do it “lazily” Art of Multiprocessor Programming

193 Art of Multiprocessor Programming
Lazy List remove() Scans list (as before) Locks predecessor & current (as before) Logical delete Marks current node as removed (new!) Physical delete Redirects predecessor’s next (as before) Art of Multiprocessor Programming

194 Art of Multiprocessor Programming
Lazy Removal a a b c d Art of Multiprocessor Programming

195 Art of Multiprocessor Programming
Lazy Removal a a b c d Present in list Art of Multiprocessor Programming

196 Art of Multiprocessor Programming
Lazy Removal a a b c d Logically deleted Art of Multiprocessor Programming 198 198

197 Art of Multiprocessor Programming
Lazy Removal a a b c d Physically deleted Art of Multiprocessor Programming

198 Art of Multiprocessor Programming
Lazy Removal a a b d Physically deleted Art of Multiprocessor Programming

199 Art of Multiprocessor Programming
Lazy List All Methods Scan through locked and marked nodes Removing a node doesn’t slow down other method calls … Must still lock pred and curr nodes. Art of Multiprocessor Programming

200 Art of Multiprocessor Programming
Validation No need to rescan list! Check that pred is not marked Check that curr is not marked Check that pred points to curr Art of Multiprocessor Programming

201 Art of Multiprocessor Programming
Business as Usual a b c Art of Multiprocessor Programming

202 Art of Multiprocessor Programming
Business as Usual a b c Art of Multiprocessor Programming

203 Art of Multiprocessor Programming
Business as Usual a b c Art of Multiprocessor Programming

204 Art of Multiprocessor Programming
Business as Usual a b c remove(b) Art of Multiprocessor Programming

205 Art of Multiprocessor Programming
Business as Usual a b c a not marked Art of Multiprocessor Programming

206 Art of Multiprocessor Programming
Business as Usual a b c a still points to b Art of Multiprocessor Programming

207 Art of Multiprocessor Programming
Business as Usual a b c Logical delete Art of Multiprocessor Programming

208 Art of Multiprocessor Programming
Business as Usual a b c physical delete Art of Multiprocessor Programming

209 Art of Multiprocessor Programming
Business as Usual a b c Art of Multiprocessor Programming

210 Art of Multiprocessor Programming
New Abstraction Map S(head) = { x | there exists node a such that a reachable from head and a.item = x and a is unmarked } Art of Multiprocessor Programming

211 Art of Multiprocessor Programming
Invariant If not marked then item in the set and reachable from head and if not yet traversed it is reachable from pred Art of Multiprocessor Programming

212 Art of Multiprocessor Programming
Validation private boolean validate(Node pred, Node curr) { return !pred.marked && !curr.marked && pred.next == curr); } Art of Multiprocessor Programming

213 Art of Multiprocessor Programming
List Validate Method private boolean validate(Node pred, Node curr) { return !pred.marked && !curr.marked && pred.next == curr); } Predecessor not Logically removed Art of Multiprocessor Programming

214 Art of Multiprocessor Programming
List Validate Method private boolean validate(Node pred, Node curr) { return !pred.marked && !curr.marked && pred.next == curr); } Current not Logically removed Art of Multiprocessor Programming

215 Art of Multiprocessor Programming
List Validate Method private boolean validate(Node pred, Node curr) { return !pred.marked && !curr.marked && pred.next == curr); } Predecessor still Points to current Art of Multiprocessor Programming

216 Art of Multiprocessor Programming
Remove try { pred.lock(); curr.lock(); if (validate(pred,curr) { if (curr.key == key) { curr.marked = true; pred.next = curr.next; return true; } else { return false; }}} finally { pred.unlock(); curr.unlock(); }}} Art of Multiprocessor Programming

217 Art of Multiprocessor Programming
Remove try { pred.lock(); curr.lock(); if (validate(pred,curr) { if (curr.key == key) { curr.marked = true; pred.next = curr.next; return true; } else { return false; }}} finally { pred.unlock(); curr.unlock(); }}} Validate as before Art of Multiprocessor Programming

218 Art of Multiprocessor Programming
Remove try { pred.lock(); curr.lock(); if (validate(pred,curr) { if (curr.key == key) { curr.marked = true; pred.next = curr.next; return true; } else { return false; }}} finally { pred.unlock(); curr.unlock(); }}} Key found Art of Multiprocessor Programming

219 Art of Multiprocessor Programming
Remove try { pred.lock(); curr.lock(); if (validate(pred,curr) { if (curr.key == key) { curr.marked = true; pred.next = curr.next; return true; } else { return false; }}} finally { pred.unlock(); curr.unlock(); }}} Logical remove Art of Multiprocessor Programming

220 Art of Multiprocessor Programming
Remove try { pred.lock(); curr.lock(); if (validate(pred,curr) { if (curr.key == key) { curr.marked = true; pred.next = curr.next; return true; } else { return false; }}} finally { pred.unlock(); curr.unlock(); }}} physical remove Art of Multiprocessor Programming

221 Art of Multiprocessor Programming
Contains public boolean contains(T item) { int key = item.hashCode(); Node curr = head; while (curr.key < key) { curr = curr.next; } return curr.key == key && !curr.marked; Art of Multiprocessor Programming

222 Art of Multiprocessor Programming
Contains public boolean contains(T item) { int key = item.hashCode(); Node curr = head; while (curr.key < key) { curr = curr.next; } return curr.key == key && !curr.marked; Start at the head Art of Multiprocessor Programming

223 Art of Multiprocessor Programming
Contains public boolean contains(T item) { int key = item.hashCode(); Node curr = head; while (curr.key < key) { curr = curr.next; } return curr.key == key && !curr.marked; Search key range Art of Multiprocessor Programming

224 (nodes may have been removed)
Contains public boolean contains(T item) { int key = item.hashCode(); Node curr = head; while (curr.key < key) { curr = curr.next; } return curr.key == key && !curr.marked; Traverse without locking (nodes may have been removed) Art of Multiprocessor Programming

225 Art of Multiprocessor Programming
Contains public boolean contains(T item) { int key = item.hashCode(); Node curr = head; while (curr.key < key) { curr = curr.next; } return curr.key == key && !curr.marked; Present and undeleted? Art of Multiprocessor Programming

226 Summary: Wait-free Contains
a b d c e Use Mark bit + list ordering Not marked → in the set Marked or missing → not in the set Art of Multiprocessor Programming

227 Art of Multiprocessor Programming
Lazy List a a b 1 d c e Lazy add()and remove() + Wait-free contains() Art of Multiprocessor Programming

228 Art of Multiprocessor Programming
Evaluation Good: contains() doesn’t lock In fact, its wait-free! Good because typically high % contains() Uncontended calls don’t re-traverse Bad Contended add() and remove() calls must re-traverse Traffic jam if one thread delays Art of Multiprocessor Programming

229 Art of Multiprocessor Programming
Traffic Jam Any concurrent data structure based on mutual exclusion has a weakness If one thread Enters critical section And “eats the big muffin” Cache miss, page fault, descheduled … Everyone else using that lock is stuck! Need to trust the scheduler…. Art of Multiprocessor Programming

230 Reminder: Lock-Free Data Structures
No matter what … Guarantees minimal progress in any execution i.e. Some thread will always complete a method call Even if others halt at malicious times Implies that implementation can’t use locks Art of Multiprocessor Programming

231 Art of Multiprocessor Programming
Lock-free Lists Next logical step Wait-free contains() lock-free add() and remove() Use only compareAndSet() What could go wrong? Art of Multiprocessor Programming

232 Art of Multiprocessor Programming
compareAndSet public abstract class CASObject { private int value; public boolean synchronized compareAndSet(int expected, int update) { if (value==expected) { value = update; return true; } return false; } … } Art of Multiprocessor Programming

233 Art of Multiprocessor Programming
compareAndSet public abstract class CASObject { private int value; public boolean synchronized compareAndSet(int expected, int update) { if (value==expected) { value = update; return true; } return false; } … } If value is as expected, … Art of Multiprocessor Programming

234 Art of Multiprocessor Programming
compareAndSet public abstract class CASOBJECT{ private int value; public boolean synchronized compareAndSet(int expected, int update) { if (value==expected) { value = update; return true; } return false; } … } … replace it Art of Multiprocessor Programming

235 Art of Multiprocessor Programming
compareAndSet public abstract class RMWRegister { private int value; public boolean synchronized compareAndSet(int expected, int update) { if (value==expected) { value = update; return true; } return false; } … } Report success Art of Multiprocessor Programming

236 Art of Multiprocessor Programming
compareAndSet public abstract class RMWRegister { private int value; public boolean synchronized compareAndSet(int expected, int update) { if (value==expected) { value = update; return true; } return false; } … } Otherwise report failure Art of Multiprocessor Programming

237 Art of Multiprocessor Programming
Lock-free Lists Logical Removal a a b 1 c c e Use CAS to verify pointer is correct Physical Removal Not enough! Art of Multiprocessor Programming 239 239

238 Art of Multiprocessor Programming
Problem… Logical Removal a a b 1 c c e d Physical Removal Node added Art of Multiprocessor Programming

239 The Solution: Combine Bit and Pointer
Logical Removal = Set Mark Bit a a b 1 c c e d Physical Removal CAS Fail CAS: Node not added after logical Removal Mark-Bit and Pointer are CASed together (AtomicMarkableReference) Art of Multiprocessor Programming

240 Art of Multiprocessor Programming
Solution Use AtomicMarkableReference Atomically Swing reference and Update flag Remove in two steps Set mark bit in next field Redirect predecessor’s pointer Art of Multiprocessor Programming

241 Art of Multiprocessor Programming
Marking a Node AtomicMarkableReference class Java.util.concurrent.atomic package Reference address F mark bit Art of Multiprocessor Programming

242 Extracting Reference & Mark
public Object get(boolean[] marked); Art of Multiprocessor Programming

243 Extracting Reference & Mark
public Object get(boolean[] marked); Returns mark at array index 0! Returns reference Art of Multiprocessor Programming

244 Art of Multiprocessor Programming
Extracting Mark Only public boolean isMarked(); Value of mark Art of Multiprocessor Programming

245 Art of Multiprocessor Programming
Changing State public boolean compareAndSet( Object expectedRef, Object updateRef, boolean expectedMark, boolean updateMark); Art of Multiprocessor Programming

246 If this is the current reference … And this is the current mark …
Changing State If this is the current reference … public boolean compareAndSet( Object expectedRef, Object updateRef, boolean expectedMark, boolean updateMark); And this is the current mark … Art of Multiprocessor Programming

247 …then change to this new reference …
Changing State …then change to this new reference … public boolean compareAndSet( Object expectedRef, Object updateRef, boolean expectedMark, boolean updateMark); … and this new mark Art of Multiprocessor Programming

248 Art of Multiprocessor Programming
Changing State public boolean attemptMark( Object expectedRef, boolean updateMark); Art of Multiprocessor Programming

249 If this is the current reference …
Changing State public boolean attemptMark( Object expectedRef, boolean updateMark); If this is the current reference … Art of Multiprocessor Programming

250 .. then change to this new mark.
Changing State public boolean attemptMark( Object expectedRef, boolean updateMark); .. then change to this new mark. Art of Multiprocessor Programming

251 Art of Multiprocessor Programming
Removing a Node CAS a b c d remove(c) Art of Multiprocessor Programming

252 Art of Multiprocessor Programming
Removing a Node failed CAS CAS a b c d remove(c) remove(b) Art of Multiprocessor Programming

253 Art of Multiprocessor Programming
Removing a Node a b c d remove(c) remove(b) Art of Multiprocessor Programming

254 Art of Multiprocessor Programming
Removing a Node a d remove(c) remove(b) Art of Multiprocessor Programming

255 Art of Multiprocessor Programming
Traversing the List Q: what do you do when you find a “logically” deleted node in your path? A: finish the job. CAS the predecessor’s next field Proceed (repeat as needed) Art of Multiprocessor Programming

256 Lock-Free Traversal (only Add and Remove)
pred curr CAS pred curr a b c d Uh-oh Art of Multiprocessor Programming

257 Art of Multiprocessor Programming
The Window Class class Window { public Node pred; public Node curr; Window(Node pred, Node curr) { pred = pred; curr = curr; } Art of Multiprocessor Programming

258 A container for pred and current values
The Window Class class Window { public Node pred; public Node curr; Window(Node pred, Node curr) { pred = pred; curr = curr; } A container for pred and current values Art of Multiprocessor Programming

259 Art of Multiprocessor Programming
Using the Find Method Window window = find(head, key); Node pred = window.pred; curr = window.curr; Art of Multiprocessor Programming

260 Art of Multiprocessor Programming
Using the Find Method Window window = find(head, key); Node pred = window.pred; curr = window.curr; Find returns window Art of Multiprocessor Programming

261 Art of Multiprocessor Programming
Using the Find Method Window window = find(head, key); Node pred = window.pred; curr = window.curr; Extract pred and curr Art of Multiprocessor Programming

262 Art of Multiprocessor Programming© Herlihy-Shavit 2007
The Find Method Window window = find(item); item At some instant, or … pred curr succ Art of Multiprocessor Programming© Herlihy-Shavit 2007

263 Art of Multiprocessor Programming© Herlihy-Shavit 2007
The Find Method Window window = find(item); item not in list At some instant, curr= null pred succ Art of Multiprocessor Programming© Herlihy-Shavit 2007

264 Art of Multiprocessor Programming
Remove public boolean remove(T item) { Boolean snip; while (true) { Window window = find(head, key); Node pred = window.pred, curr = window.curr; if (curr.key != key) { return false; } else { Node succ = curr.next.getReference(); snip = curr.next.compareAndSet(succ, succ, false true); if (!snip) continue; pred.next.compareAndSet(curr, succ, false, false); return true; }}} Art of Multiprocessor Programming

265 Art of Multiprocessor Programming
Remove public boolean remove(T item) { Boolean snip; while (true) { Window window = find(head, key); Node pred = window.pred, curr = window.curr; if (curr.key != key) { return false; } else { Node succ = curr.next.getReference(); snip = curr.next.compareAndSet (succ, succ, false, true); if (!snip) continue; pred.next.compareAndSet(curr, succ, false, false); return true; }}} Keep trying Art of Multiprocessor Programming

266 Art of Multiprocessor Programming
Remove public boolean remove(T item) { Boolean snip; while (true) { Window window = find(head, key); Node pred = window.pred, curr = window.curr; if (curr.key != key) { return false; } else { Node succ = curr.next.getReference(); snip = curr.next.compareAndSet (succ, succ, false, true); if (!snip) continue; pred.next.compareAndSet(curr, succ, false, false); return true; }}} Find neighbors Art of Multiprocessor Programming

267 Art of Multiprocessor Programming
Remove public boolean remove(T item) { Boolean snip; while (true) { Window window = find(head, key); Node pred = window.pred, curr = window.curr; if (curr.key != key) { return false; } else { Node succ = curr.next.getReference(); snip = curr.next.compareAndSet(succ, succ, false, true); if (!snip) continue; pred.next.compareAndSet(curr, succ, false, false); return true; }}} Not there … Art of Multiprocessor Programming

268 Try to mark node as deleted
Remove public boolean remove(T item) { Boolean snip; while (true) { Window window = find(head, key); Node pred = window.pred, curr = window.curr; if (curr.key != key) { return false; } else { Node succ = curr.next.getReference(); snip = curr.next.compareAndSet(succ, succ, false, true); if (!snip) continue; pred.next.compareAndSet(curr, succ, false, false); return true; }}} Try to mark node as deleted Art of Multiprocessor Programming

269 If it doesn’t work, just retry, if it does, job essentially done
Remove public boolean remove(T item) { Boolean snip; while (true) { Window window = find(head, key); Node pred = window.pred, curr = window.curr; if (curr.key != key) { return false; } else { Node succ = curr.next.getReference(); snip = curr.next.compareAndSet(succ, succ, false, true); if (!snip) continue; pred.next.compareAndSet(curr, succ, false, false); return true; }}} If it doesn’t work, just retry, if it does, job essentially done Art of Multiprocessor Programming

270 Art of Multiprocessor Programming
Remove public boolean remove(T item) { Boolean snip; while (true) { Window window = find(head, key); Node pred = window.pred, curr = window.curr; if (curr.key != key) { return false; } else { Node succ = curr.next.getReference(); snip = curr.next.compareAndSet(succ, succ, false, true); if (!snip) continue; pred.next.compareAndSet(curr, succ, false, false); return true; }}} a Try to advance reference (if we don’t succeed, someone else did or will). If we don’t succeed then either someone already removed curr, or someone modified pred, for example, by inserting another node as pred’s successor, in which case we need not worry since some other later thread that will attempt to traverse the list will remove the marked curr node before traversing beyond it. Art of Multiprocessor Programming

271 Art of Multiprocessor Programming
Add public boolean add(T item) { boolean splice; while (true) { Window window = find(head, key); Node pred = window.pred, curr = window.curr; if (curr.key == key) { return false; } else { Node node = new Node(item); node.next = new AtomicMarkableRef(curr, false); if (pred.next.compareAndSet(curr, node, false, false)) {return true;} }}} Art of Multiprocessor Programming

272 Art of Multiprocessor Programming
Add public boolean add(T item) { boolean splice; while (true) { Window window = find(head, key); Node pred = window.pred, curr = window.curr; if (curr.key == key) { return false; } else { Node node = new Node(item); node.next = new AtomicMarkableRef(curr, false); if (pred.next.compareAndSet(curr, node, false, false)) {return true;} }}} Item already there Art of Multiprocessor Programming

273 Art of Multiprocessor Programming
Add public boolean add(T item) { boolean splice; while (true) { Window window = find(head, key); Node pred = window.pred, curr = window.curr; if (curr.key == key) { return false; } else { Node node = new Node(item); node.next = new AtomicMarkableRef(curr, false); if (pred.next.compareAndSet(curr, node, false, false)) {return true;} }}} create new node Art of Multiprocessor Programming

274 Install new node, else retry loop
Add public boolean add(T item) { boolean splice; while (true) { Window window = find(head, key); Node pred = window.pred, curr = window.curr; if (curr.key == key) { return false; } else { Node node = new Node(item); node.next = new AtomicMarkableRef(curr, false); if (pred.next.compareAndSet(curr, node, false, false)) {return true;} }}} Install new node, else retry loop Art of Multiprocessor Programming

275 Art of Multiprocessor Programming
Wait-free Contains public boolean contains(T item) { boolean marked; int key = item.hashCode(); Node curr = head; while (curr.key < key) curr = curr.next; Node succ = curr.next.get(marked); return (curr.key == key && !marked[0]) } The wait-free \mContains{} method of the \cLockFreeList{} is the same as that of the \cLazyList{} with one small change: to test if \fCurr{} is marked we apply \lstinline+curr.next.get(marked)+ and check that \aMarked{0} is true. Art of Multiprocessor Programming

276 Only difference is that we get and check marked
Wait-free Contains public boolean contains(T item) { boolean marked; int key = item.hashCode(); Node curr = head; while (curr.key < key) curr = curr.next; Node succ = curr.next.get(marked); return (curr.key == key && !marked[0]) } Only difference is that we get and check marked The wait-free \mContains{} method of the \cLockFreeList{} is the same as that of the \cLazyList{} with one small change: to test if \fCurr{} is marked we apply \lstinline+curr.next.get(marked)+ and check that \aMarked{0} is true. Art of Multiprocessor Programming

277 Art of Multiprocessor Programming
Lock-free Find public Window find(Node head, int key) { Node pred = null, curr = null, succ = null; boolean[] marked = {false}; boolean snip; retry: while (true) { pred = head; curr = pred.next.getReference(); while (true) { succ = curr.next.get(marked); while (marked[0]) { } if (curr.key >= key) return new Window(pred, curr); pred = curr; curr = succ; }} Art of Multiprocessor Programming

278 If list changes while traversed, start over
Lock-free Find public Window find(Node head, int key) { Node pred = null, curr = null, succ = null; boolean[] marked = {false}; boolean snip; retry: while (true) { pred = head; curr = pred.next.getReference(); while (true) { succ = curr.next.get(marked); while (marked[0]) { } if (curr.key >= key) return new Window(pred, curr); pred = curr; curr = succ; }} If list changes while traversed, start over Art of Multiprocessor Programming

279 Start looking from head
Lock-free Find public Window find(Node head, int key) { Node pred = null, curr = null, succ = null; boolean[] marked = {false}; boolean snip; retry: while (true) { pred = head; curr = pred.next.getReference(); while (true) { succ = curr.next.get(marked); while (marked[0]) { } if (curr.key >= key) return new Window(pred, curr); pred = curr; curr = succ; }} Start looking from head Art of Multiprocessor Programming

280 Art of Multiprocessor Programming
Lock-free Find public Window find(Node head, int key) { Node pred = null, curr = null, succ = null; boolean[] marked = {false}; boolean snip; retry: while (true) { pred = head; curr = pred.next.getReference(); while (true) { succ = curr.next.get(marked); while (marked[0]) { } if (curr.key >= key) return new Window(pred, curr); pred = curr; curr = succ; }} Move down the list Art of Multiprocessor Programming

281 Get ref to successor and current deleted bit
Lock-free Find public Window find(Node head, int key) { Node pred = null, curr = null, succ = null; boolean[] marked = {false}; boolean snip; retry: while (true) { pred = head; curr = pred.next.getReference(); while (true) { succ = curr.next.get(marked); while (marked[0]) { } if (curr.key >= key) return new Window(pred, curr); pred = curr; curr = succ; }} Get ref to successor and current deleted bit Art of Multiprocessor Programming

282 Try to remove deleted nodes in path…code details soon
Lock-free Find public Window find(Node head, int key) { Node pred = null, curr = null, succ = null; boolean[] marked = {false}; boolean snip; retry: while (true) { pred = head; curr = pred.next.getReference(); while (true) { succ = curr.next.get(marked); while (marked[0]) { } if (curr.key >= key) return new Window(pred, curr); pred = curr; curr = succ; }} Try to remove deleted nodes in path…code details soon Art of Multiprocessor Programming

283 If curr key that is greater or equal, return pred and curr
Lock-free Find public Window find(Node head, int key) { Node pred = null, curr = null, succ = null; boolean[] marked = {false}; boolean snip; retry: while (true) { pred = head; curr = pred.next.getReference(); while (true) { succ = curr.next.get(marked); while (marked[0]) { } if (curr.key >= key) return new Window(pred, curr); pred = curr; curr = succ; }} If curr key that is greater or equal, return pred and curr Art of Multiprocessor Programming

284 Otherwise advance window and loop again
Lock-free Find public Window find(Node head, int key) { Node pred = null, curr = null, succ = null; boolean[] marked = {false}; boolean snip; retry: while (true) { pred = head; curr = pred.next.getReference(); while (true) { succ = curr.next.get(marked); while (marked[0]) { } if (curr.key >= key) return new Window(pred, curr); pred = curr; curr = succ; }} Otherwise advance window and loop again Art of Multiprocessor Programming

285 Art of Multiprocessor Programming
Lock-free Find retry: while (true) { while (marked[0]) { snip = pred.next.compareAndSet(curr, succ, false, false); if (!snip) continue retry; curr = succ; succ = curr.next.get(marked); } Art of Multiprocessor Programming

286 Art of Multiprocessor Programming
Lock-free Find Try to snip out node retry: while (true) { while (marked[0]) { snip = pred.next.compareAndSet(curr, succ, false, false); if (!snip) continue retry; curr = succ; succ = curr.next.get(marked); } Art of Multiprocessor Programming

287 if predecessor’s next field changed, retry whole traversal
Lock-free Find if predecessor’s next field changed, retry whole traversal retry: while (true) { while (marked[0]) { snip = pred.next.compareAndSet(curr, succ, false, false); if (!snip) continue retry; curr = succ; succ = curr.next.get(marked); } Art of Multiprocessor Programming

288 Otherwise move on to check if next node deleted
Lock-free Find Otherwise move on to check if next node deleted retry: while (true) { while (marked[0]) { snip = pred.next.compareAndSet(curr, succ, false, false); if (!snip) continue retry; curr = succ; succ = curr.next.get(marked); } Art of Multiprocessor Programming

289 Art of Multiprocessor Programming
Performance Different list-based set implementaions 16-node machine Vary percentage of contains() calls Art of Multiprocessor Programming

290 Art of Multiprocessor Programming
High Contains Ratio Lock-free Lazy list Coarse Grained Fine Lock-coupling Art of Multiprocessor Programming

291 Art of Multiprocessor Programming
Low Contains Ratio Lock-free Lazy list Coarse Grained Fine Lock-coupling Art of Multiprocessor Programming

292 As Contains Ratio Increases
Lock-free Lazy list Coarse Grained Fine Lock-coupling % Contains() Art of Multiprocessor Programming

293 Art of Multiprocessor Programming
Summary Coarse-grained locking Fine-grained locking Optimistic synchronization Lazy synchronization Lock-free synchronization We saw 4 approaches to concurrent data structure design. Art of Multiprocessor Programming

294 Art of Multiprocessor Programming
“To Lock or Not to Lock” Locking vs. Non-blocking: Extremist views on both sides The answer: nobler to compromise Example: Lazy list combines blocking add() and remove()and a wait-free contains() Remember: Blocking/non-blocking is a property of a method We should make sure to notice that being blocking or lock-free or wait-free is a property of a method, and that individual methods of a given item implementation don’t necessarily provide the same properties (as in the lazy list). Art of Multiprocessor Programming

295 Art of Multiprocessor Programming
          This work is licensed under a Creative Commons Attribution-ShareAlike 2.5 License. You are free: to Share — to copy, distribute and transmit the work to Remix — to adapt the work Under the following conditions: Attribution. You must attribute the work to “The Art of Multiprocessor Programming” (but not in any way that suggests that the authors endorse you or your use of the work). Share Alike. If you alter, transform, or build upon this work, you may distribute the resulting work only under the same, similar or a compatible license. For any reuse or distribution, you must make clear to others the license terms of this work. The best way to do this is with a link to Any of the above conditions can be waived if you get permission from the copyright holder. Nothing in this license impairs or restricts the author's moral rights. Art of Multiprocessor Programming


Download ppt "Linked Lists: Locking, Lock-Free, and Beyond …"

Similar presentations


Ads by Google