Presentation is loading. Please wait.

Presentation is loading. Please wait.

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

Similar presentations


Presentation on theme: "Linked Lists: Locking, Lock-Free, and Beyond … Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit."— Presentation transcript:

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

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

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

4 Art of Multiprocessor Programming4 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

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

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

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

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

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

10 Art of Multiprocessor Programming10 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 …

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

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

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

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

15 Art of Multiprocessor Programming15 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

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

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

18 Art of Multiprocessor Programming18 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

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

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

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

22 Art of Multiprocessor Programming22 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

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

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

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

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

27 Art of Multiprocessor Programming27 Set Interface Unordered collection of items

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

29 Art of Multiprocessor Programming29 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

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

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

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

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

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

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

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

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

38 Art of Multiprocessor Programming38 The List-Based Set abc Sorted with Sentinel nodes (min & max possible keys) -∞ +∞

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

40 Art of Multiprocessor Programming40 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

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

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

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

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

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

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

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

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

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

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

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

52 Art of Multiprocessor Programming52 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

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

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

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

56 Art of Multiprocessor Programming56 Sequential List Based Set a c d b a b c add() r emove()

57 Art of Multiprocessor Programming57 Coarse-Grained Locking a b d

58 Art of Multiprocessor Programming58 Coarse-Grained Locking a b d c

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

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

61 Art of Multiprocessor Programming61 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

62 Art of Multiprocessor Programming62 Fine-grained Locking Requires careful thought –“Do not meddle in the affairs of wizards, for they are subtle and quick to anger”

63 Art of Multiprocessor Programming63 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

64 Art of Multiprocessor Programming64 Hand-over-Hand locking abc

65 Art of Multiprocessor Programming65 Hand-over-Hand locking abc

66 Art of Multiprocessor Programming66 Hand-over-Hand locking abc

67 Art of Multiprocessor Programming67 Hand-over-Hand locking abc

68 Art of Multiprocessor Programming68 Hand-over-Hand locking abc

69 Art of Multiprocessor Programming69 Removing a Node abcd remove(b)

70 Art of Multiprocessor Programming70 Removing a Node abcd remove(b)

71 Art of Multiprocessor Programming71 Removing a Node abcd remove(b)

72 Art of Multiprocessor Programming72 Removing a Node abcd remove(b)

73 Art of Multiprocessor Programming73 Removing a Node abcd remove(b)

74 Art of Multiprocessor Programming74 Removing a Node acd remove(b) Why lock victim node?

75 Art of Multiprocessor Programming75 Concurrent Removes abcd remove(c) remove(b)

76 Art of Multiprocessor Programming76 Concurrent Removes abcd remove(b) remove(c)

77 Art of Multiprocessor Programming77 Concurrent Removes abcd remove(b) remove(c)

78 Art of Multiprocessor Programming78 Concurrent Removes abcd remove(b) remove(c)

79 Art of Multiprocessor Programming79 Concurrent Removes abcd remove(b) remove(c)

80 Art of Multiprocessor Programming80 Concurrent Removes abcd remove(b) remove(c)

81 Art of Multiprocessor Programming81 Concurrent Removes abcd remove(b) remove(c)

82 Art of Multiprocessor Programming82 Concurrent Removes abcd remove(b) remove(c)

83 Art of Multiprocessor Programming83 Concurrent Removes abcd remove(b) remove(c)

84 Art of Multiprocessor Programming84 Concurrent Removes abcd remove(b) remove(c)

85 Art of Multiprocessor Programming85 Uh, Oh acd remove(b) remove(c)

86 Art of Multiprocessor Programming86 Uh, Oh acd Bad news, c not removed remove(b) remove(c)

87 Art of Multiprocessor Programming87 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 ba cbac

88 Art of Multiprocessor Programming88 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

89 Art of Multiprocessor Programming89 Hand-Over-Hand Again abcd remove(b)

90 Art of Multiprocessor Programming90 Hand-Over-Hand Again abcd remove(b)

91 Art of Multiprocessor Programming91 Hand-Over-Hand Again abcd remove(b)

92 Art of Multiprocessor Programming92 Hand-Over-Hand Again abcd remove(b) Found it!

93 Art of Multiprocessor Programming93 Hand-Over-Hand Again abcd remove(b) Found it!

94 Art of Multiprocessor Programming94 Hand-Over-Hand Again acd remove(b)

95 Art of Multiprocessor Programming95 Removing a Node abcd remove(b) remove(c)

96 Art of Multiprocessor Programming96 Removing a Node abcd remove(b) remove(c)

97 Art of Multiprocessor Programming97 Removing a Node abcd remove(b) remove(c)

98 Art of Multiprocessor Programming98 Removing a Node abcd remove(b) remove(c)

99 Art of Multiprocessor Programming99 Removing a Node abcd remove(b) remove(c)

100 Art of Multiprocessor Programming100 Removing a Node abcd remove(b) remove(c)

101 Art of Multiprocessor Programming101 Removing a Node abcd remove(b) remove(c)

102 Art of Multiprocessor Programming102 Removing a Node abcd remove(b) remove(c)

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

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

105 Art of Multiprocessor Programming105 Removing a Node abcd Wait! remove(c)

106 Art of Multiprocessor Programming106 Removing a Node abd Proceed to remove(b)

107 Art of Multiprocessor Programming107 Removing a Node abd remove(b)

108 Art of Multiprocessor Programming108 Removing a Node abd remove(b)

109 Art of Multiprocessor Programming109 Removing a Node ad remove(b)

110 Art of Multiprocessor Programming110 Removing a Node ad

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

112 Art of Multiprocessor Programming112 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

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

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

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

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

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

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

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

120 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 Programming120 Remove: searching

121 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 Programming121 Remove: searching Search key range

122 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 Programming122 Remove: searching

123 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 Programming123 Remove: searching If item found, remove node

124 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 Programming124 Remove: searching If node found, remove it

125 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 Programming125 Remove: searching Unlock predecessor

126 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 Programming126 Remove: searching Only one node locked!

127 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 Programming127 Remove: searching demote current

128 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; Art of Multiprocessor Programming128 Remove: searching Find and lock new current

129 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; Art of Multiprocessor Programming129 Remove: searching Lock invariant restored

130 Art of Multiprocessor Programming130 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

131 Art of Multiprocessor Programming131 Why does this work? To remove node e –Must lock e –Must lock e’s predecessor Therefore, if you lock a node –It can’t be removed –And neither can its successor

132 Art of Multiprocessor Programming132 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; Why remove() is linearizable pred reachable from head curr is pred.next So curr.item is in the set

133 Art of Multiprocessor Programming133 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; Why remove() is linearizable Linearization point if item is present

134 Art of Multiprocessor Programming134 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; Why remove() is linearizable Node locked, so no other thread can remove it ….

135 Art of Multiprocessor Programming135 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; Why remove() is linearizable Item not present

136 Art of Multiprocessor Programming136 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; Why remove() is linearizable pred reachable from head curr is pred.next pred.key < key key < curr.key

137 Art of Multiprocessor Programming137 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; Why remove() is linearizable Linearization point

138 Art of Multiprocessor Programming138 Adding Nodes To add node e –Must lock predecessor –Must lock successor Neither can be deleted –(Is successor lock actually required?)

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

140 Art of Multiprocessor Programming140 Rep Invariant Easy to check that –tail always reachable from head –Nodes sorted, no duplicates

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

142 Art of Multiprocessor Programming142 Optimistic Synchronization Find nodes without locking Lock nodes Check that everything is OK

143 Art of Multiprocessor Programming143 Optimistic: Traverse without Locking b d e a add(c) Aha!

144 Art of Multiprocessor Programming144 Optimistic: Lock and Load b d e a add(c)

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

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

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

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

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

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

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

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

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

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

155 Art of Multiprocessor Programming155 What Else Coould Go Wrong? b d e a add(c) add(b’)

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

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

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

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

160 Art of Multiprocessor Programming160 Optimistic: Linearization Point b d e a add(c) c

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

162 Art of Multiprocessor Programming162 Invariants Careful: we may traverse deleted nodes But we establish properties by –Validation –After we lock target nodes

163 Art of Multiprocessor Programming163 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

164 Art of Multiprocessor Programming164 Unsuccessful Remove abde remove(c) Aha!

165 Art of Multiprocessor Programming165 Validate (1) abde Yes, b still reachable from head remove(c)

166 Art of Multiprocessor Programming166 Validate (2) abde remove(c) Yes, b still points to d

167 Art of Multiprocessor Programming167 OK Computer abde remove(c) return false

168 Art of Multiprocessor Programming168 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

169 Art of Multiprocessor Programming169 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; }

170 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 Programming170 Validation Predecessor & current nodes

171 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 Programming171 Validation Begin at the beginning

172 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 Programming172 Validation Search range of keys

173 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 Programming173 Validation Predecessor reachable

174 Art of Multiprocessor Programming174 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; } Validation Is current node next?

175 Art of Multiprocessor Programming175 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; } Validation Otherwise move on

176 Art of Multiprocessor Programming176 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; } Validation Predecessor not reachable

177 Art of Multiprocessor Programming177 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; } …

178 Art of Multiprocessor Programming178 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; } … Remove: searching Search key

179 Art of Multiprocessor Programming179 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; } … Remove: searching Retry on synchronization conflict

180 Art of Multiprocessor Programming180 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; } … Remove: searching Examine predecessor and current nodes

181 Art of Multiprocessor Programming181 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; } … Remove: searching Search by key

182 Art of Multiprocessor Programming182 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; } … Remove: searching Stop if we find item

183 Art of Multiprocessor Programming183 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; } … Remove: searching Move along

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

185 Art of Multiprocessor Programming185 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(); }}}

186 Art of Multiprocessor Programming186 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(); }}} Remove Method Always unlock

187 Art of Multiprocessor Programming187 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(); }}} Remove Method Lock both nodes

188 Art of Multiprocessor Programming188 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(); }}} Remove Method Check for synchronization conflicts

189 Art of Multiprocessor Programming189 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(); }}} Remove Method target found, remove node

190 Art of Multiprocessor Programming190 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(); }}} Remove Method target not found

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

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

193 Art of Multiprocessor Programming193 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

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

195 Art of Multiprocessor Programming195 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)

196 Art of Multiprocessor Programming196 Lazy Removal aa b c d

197 c Art of Multiprocessor Programming197 Lazy Removal aa b d Present in list

198 c Art of Multiprocessor Programming198 Lazy Removal aa b d Logically deleted

199 Art of Multiprocessor Programming199 Lazy Removal aa b c d Physically deleted

200 Art of Multiprocessor Programming200 Lazy Removal aa b d Physically deleted

201 Art of Multiprocessor Programming201 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.

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

203 Art of Multiprocessor Programming203 Business as Usual abc

204 Art of Multiprocessor Programming204 Business as Usual abc

205 Art of Multiprocessor Programming205 Business as Usual abc

206 Art of Multiprocessor Programming206 Business as Usual abc remove(b)

207 Art of Multiprocessor Programming207 Business as Usual abc a not marked

208 Art of Multiprocessor Programming208 Business as Usual abc a still points to b

209 Art of Multiprocessor Programming209 Business as Usual a bc Logical delete

210 Art of Multiprocessor Programming210 Business as Usual a bc physical delete

211 Art of Multiprocessor Programming211 Business as Usual a bc

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

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

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

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

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

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

218 Art of Multiprocessor Programming218 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(); }}}

219 Art of Multiprocessor Programming219 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

220 Art of Multiprocessor Programming220 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

221 Art of Multiprocessor Programming221 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

222 Art of Multiprocessor Programming222 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

223 Art of Multiprocessor Programming223 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; }

224 Art of Multiprocessor Programming224 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

225 Art of Multiprocessor Programming225 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

226 Art of Multiprocessor Programming226 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)

227 Art of Multiprocessor Programming227 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?

228 Art of Multiprocessor Programming228 Summary: Wait-free Contains a 0 0 a b c e d Use Mark bit + list ordering 1.Not marked  in the set 2.Marked or missing  not in the set

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

230 Art of Multiprocessor Programming230 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

231 Art of Multiprocessor Programming231 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….

232 Art of Multiprocessor Programming232 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

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

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

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

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

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

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

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

240 Art of Multiprocessor Programming240 Problem… a 0 0 0 a b c 0 e 1 c Logical Removal Physical Removal 0 d Node added

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

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

243 Art of Multiprocessor Programming243 Marking a Node AtomicMarkableReference class –Java.util.concurrent.atomic package address F mark bit Reference

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

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

246 Art of Multiprocessor Programming246 Extracting Mark Only public boolean isMarked(); Value of mark

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

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

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

250 Art of Multiprocessor Programming250 Changing State public boolean attemptMark( Object expectedRef, boolean updateMark);

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

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

253 b CAS Art of Multiprocessor Programming253 Removing a Node acd remove(c)

254 Art of Multiprocessor Programming254 Removing a Node abd remove(b) c failed CAS remove(c)

255 Art of Multiprocessor Programming255 Removing a Node abd c remove(b) remove(c)

256 Art of Multiprocessor Programming256 Removing a Node ad remove(b) remove(c)

257 Art of Multiprocessor Programming257 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)

258 Art of Multiprocessor Programming258 Lock-Free Traversal (only Add and Remove) abcd CAS Uh-oh pred curr pred curr

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

260 Art of Multiprocessor Programming260 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

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

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

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

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

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

266 Art of Multiprocessor Programming266 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; }}}

267 Art of Multiprocessor Programming267 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

268 Art of Multiprocessor Programming268 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

269 Art of Multiprocessor Programming269 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 …

270 Art of Multiprocessor Programming270 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

271 Art of Multiprocessor Programming271 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

272 Art of Multiprocessor Programming272 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 advance reference (if we don’t succeed, someone else did or will). Try to advance reference (if we don’t succeed, someone else did or will). a

273 Art of Multiprocessor Programming273 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;} }}}

274 Art of Multiprocessor Programming274 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

275 Art of Multiprocessor Programming275 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

276 Art of Multiprocessor Programming276 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

277 Art of Multiprocessor Programming277 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]) }

278 Art of Multiprocessor Programming278 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

279 Art of Multiprocessor Programming279 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; } }}

280 Art of Multiprocessor Programming280 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

281 Art of Multiprocessor Programming281 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; } }} Lock-free Find Start looking from head

282 Art of Multiprocessor Programming282 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; } }} Lock-free Find Move down the list

283 Art of Multiprocessor Programming283 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; } }} Lock-free Find Get ref to successor and current deleted bit

284 Art of Multiprocessor Programming284 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; } }} Lock-free Find Try to remove deleted nodes in path…code details soon

285 Art of Multiprocessor Programming285 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; } }} Lock-free Find If curr key that is greater or equal, return pred and curr

286 Art of Multiprocessor Programming286 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; } }} Lock-free Find Otherwise advance window and loop again

287 Art of Multiprocessor Programming287 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); } …

288 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 Programming288 Lock-free Find Try to snip out node

289 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 Programming289 Lock-free Find if predecessor’s next field changed, retry whole traversal

290 Art of Multiprocessor Programming290 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); } … Otherwise move on to check if next node deleted

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

292 Art of Multiprocessor Programming292 High Contains Ratio Lock-free Lazy list Coarse Grained Fine Lock-coupling

293 Art of Multiprocessor Programming293 Low Contains Ratio

294 Art of Multiprocessor Programming294 As Contains Ratio Increases % Contains()

295 Art of Multiprocessor Programming295 Summary Coarse-grained locking Fine-grained locking Optimistic synchronization Lazy synchronization Lock-free synchronization

296 Art of Multiprocessor Programming296 “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

297 Art of Multiprocessor Programming297 This work is licensed under a Creative Commons Attribution- ShareAlike 2.5 License.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 –http://creativecommons.org/licenses/by-sa/3.0/. 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.


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

Similar presentations


Ads by Google