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

advertisement
Linked Lists: Locking, LockFree, and Beyond …
Based on the companion slides for
The Art of Multiprocessor
Programming
(Maurice Herlihy & Nir Shavit)
Coarse-Grained
Synchronization
• Each method locks the object
– Easy to reason about
• In simple cases
– Standard Java model
• Synchronized blocks and methods
• So, are we done?
Art of Multiprocessor Programming© Herlihy-Shavit 2007
2
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© Herlihy-Shavit 2007
3
This Lecture
• Introduce four “patterns”
– Bag of tricks …
– Methods that work more than once …
• For highly-concurrent objects
• Goal:
– Concurrent access
– More threads, more throughput
Art of Multiprocessor Programming© Herlihy-Shavit 2007
4
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© Herlihy-Shavit 2007
5
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
– Mistakes are expensive
Art of Multiprocessor Programming© Herlihy-Shavit 2007
6
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© Herlihy-Shavit 2007
7
Fourth:
Lock-Free Synchronization
• Don’t use locks at all
– Use compareAndSet() & relatives …
• Advantages
– Robust against asynchrony
• Disadvantages
– Complex
– Sometimes high overhead
Art of Multiprocessor Programming© Herlihy-Shavit 2007
8
Linked List
• Illustrate these patterns …
• Using a list-based Set
– Common application
– Building block for other apps
Art of Multiprocessor Programming© Herlihy-Shavit 2007
9
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© Herlihy-Shavit 2007
10
Set Interface
public interface Set<T> {
public boolean add(T x);
public boolean remove(T x);
public boolean contains(T x);
}
Art of Multiprocessor Programming© Herlihy-Shavit 2007
11
Set Interface
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© Herlihy-Shavit 2007
12
Set Interface
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© Herlihy-Shavit 2007
13
Set Interface
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© Herlihy-Shavit 2007
14
List Node
public class Node {
public T item;
public int key;
public Node next;
}
Art of Multiprocessor Programming© Herlihy-Shavit 2007
15
List Node
public class Node {
public T item;
public int key;
public Node next;
}
item of interest
Art of Multiprocessor Programming© Herlihy-Shavit 2007
16
List Node
public class Node {
public T item;
public int key;
public Node next;
}
Usually hash code
Art of Multiprocessor Programming© Herlihy-Shavit 2007
17
List Node
public class Node {
public T item;
public int key;
public Node next;
}
Reference to next node
Art of Multiprocessor Programming© Herlihy-Shavit 2007
18
The List-Based Set
-∞
a
b
c
+∞
Sorted with Sentinel nodes
(min & max possible keys)
Art of Multiprocessor Programming© Herlihy-Shavit 2007
19
Reasoning about Concurrent
Objects
• Invariant
– Property that always holds
• Established by
– True when object is created
– Truth preserved by each method
• Each step of each method
Art of Multiprocessor Programming© Herlihy-Shavit 2007
20
Specifically …
• Invariants preserved by
– add()
– remove()
– contains()
• Most steps are trivial
– Usually one step tricky
– Often linearization point
Art of Multiprocessor Programming© Herlihy-Shavit 2007
21
Representation Invariants
• Sentinel nodes never added/removed
– tail reachable from head
• Elements sorted by key (hash value)
• No duplicates
Art of Multiprocessor Programming© Herlihy-Shavit 2007
22
Interference
• Invariants make sense only if
methods considered are the only
modifiers
• Language encapsulation helps
– List nodes not visible outside class
– This guarantees freedom from
interference
Art of Multiprocessor Programming© Herlihy-Shavit 2007
23
Abstract Data Types
• Concrete representation
a
b
• Abstract Type
– {a, b}
Art of Multiprocessor Programming© Herlihy-Shavit 2007
24
Abstract Data Types
• Meaning of representation given by
abstraction map
– S(
a
b
) = {a,b}
Art of Multiprocessor Programming© Herlihy-Shavit 2007
25
Abstraction Map
• S(head) =
{ x | there exists a such that
a reachable from head and
a.item = x
}
Art of Multiprocessor Programming© Herlihy-Shavit 2007
26
Sequential List Based Set
Add()
a
c
d
a
b
c
Remove()
Art of Multiprocessor Programming© Herlihy-Shavit 2007
27
Sequential List Based Set
Add()
a
c
d
b
c
b
Remove()
a
Art of Multiprocessor Programming© Herlihy-Shavit 2007
28
Sequential List Based Set
Add()
a
c
d
b
c
b
Remove()
a
Art of Multiprocessor Programming© Herlihy-Shavit 2007
29
Course Grained Locking
a
b
d
Art of Multiprocessor Programming© Herlihy-Shavit 2007
30
Course Grained Locking
a
d
b
c
Art of Multiprocessor Programming© Herlihy-Shavit 2007
31
Course Grained Locking
a
d
b
honk!
honk!
c
Simple but hotspot + bottleneck
Art of Multiprocessor Programming© Herlihy-Shavit 2007
32
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© Herlihy-Shavit 2007
33
Fine-grained Locking
• Requires careful thought
• Split object into pieces
– Each piece has own lock
– Methods that work on disjoint pieces
need not exclude each other
• Allows pipelined list traversal
Art of Multiprocessor Programming© Herlihy-Shavit 2007
34
Hand-over-Hand locking
a
b
c
Art of Multiprocessor Programming© Herlihy-Shavit 2007
35
Hand-over-Hand locking
a
b
c
Art of Multiprocessor Programming© Herlihy-Shavit 2007
36
Hand-over-Hand locking
a
b
c
Art of Multiprocessor Programming© Herlihy-Shavit 2007
37
Hand-over-Hand locking
a
b
c
Art of Multiprocessor Programming© Herlihy-Shavit 2007
38
Hand-over-Hand locking
a
b
c
Art of Multiprocessor Programming© Herlihy-Shavit 2007
39
Removing a Node
a
b
c
d
remove(b)
Art of Multiprocessor Programming© Herlihy-Shavit 2007
40
Removing a Node
a
b
c
d
remove(b)
Art of Multiprocessor Programming© Herlihy-Shavit 2007
41
Removing a Node
a
b
c
d
remove(b)
Art of Multiprocessor Programming© Herlihy-Shavit 2007
42
Removing a Node
a
b
c
d
remove(b)
Art of Multiprocessor Programming© Herlihy-Shavit 2007
43
Removing a Node
a
b
c
d
remove(b)
Art of Multiprocessor Programming© Herlihy-Shavit 2007
44
Removing a Node
a
c
d
remove(b)
Art of Multiprocessor Programming© Herlihy-Shavit 2007
45
Removing a Node
a
b
c
remove(b)
Art of Multiprocessor Programming© Herlihy-Shavit 2007
d
remove(c)
46
Removing a Node
a
b
c
remove(b)
Art of Multiprocessor Programming© Herlihy-Shavit 2007
d
remove(c)
47
Removing a Node
a
b
c
remove(b)
Art of Multiprocessor Programming© Herlihy-Shavit 2007
d
remove(c)
48
Removing a Node
a
b
c
remove(b)
Art of Multiprocessor Programming© Herlihy-Shavit 2007
d
remove(c)
49
Removing a Node
a
b
c
remove(b)
Art of Multiprocessor Programming© Herlihy-Shavit 2007
d
remove(c)
50
Removing a Node
a
b
c
remove(b)
Art of Multiprocessor Programming© Herlihy-Shavit 2007
d
remove(c)
51
Removing a Node
a
b
c
remove(b)
Art of Multiprocessor Programming© Herlihy-Shavit 2007
d
remove(c)
52
Removing a Node
a
b
c
remove(b)
Art of Multiprocessor Programming© Herlihy-Shavit 2007
d
remove(c)
53
Uh, Oh
a
c
remove(b)
Art of Multiprocessor Programming© Herlihy-Shavit 2007
d
remove(c)
54
Uh, Oh
Bad news
a
c
remove(b)
Art of Multiprocessor Programming© Herlihy-Shavit 2007
d
remove(c)
55
Problem
• To delete node b
– Swing node a’s next field to c
• Problem is,
a
b
c
– Someone could delete c concurrently
a
b
Art of Multiprocessor Programming© Herlihy-Shavit 2007
c
56
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© Herlihy-Shavit 2007
57
Hand-Over-Hand Again
a
b
c
d
remove(b)
Art of Multiprocessor Programming© Herlihy-Shavit 2007
58
Hand-Over-Hand Again
a
b
c
d
remove(b)
Art of Multiprocessor Programming© Herlihy-Shavit 2007
59
Hand-Over-Hand Again
a
b
c
d
remove(b)
Art of Multiprocessor Programming© Herlihy-Shavit 2007
60
Hand-Over-Hand Again
a
b
c
remove(b)
Art of Multiprocessor Programming© Herlihy-Shavit 2007
d
Found
it!
61
Hand-Over-Hand Again
a
b
c
remove(b)
Art of Multiprocessor Programming© Herlihy-Shavit 2007
d
Found
it!
62
Hand-Over-Hand Again
a
c
d
remove(b)
Art of Multiprocessor Programming© Herlihy-Shavit 2007
63
Removing a Node
a
b
c
remove(b)
Art of Multiprocessor Programming© Herlihy-Shavit 2007
d
remove(c)
64
Removing a Node
a
b
c
remove(b)
Art of Multiprocessor Programming© Herlihy-Shavit 2007
d
remove(c)
65
Removing a Node
a
b
c
remove(b)
Art of Multiprocessor Programming© Herlihy-Shavit 2007
d
remove(c)
66
Removing a Node
a
b
c
remove(b)
Art of Multiprocessor Programming© Herlihy-Shavit 2007
d
remove(c)
67
Removing a Node
a
b
c
remove(b)
Art of Multiprocessor Programming© Herlihy-Shavit 2007
d
remove(c)
68
Removing a Node
a
b
c
remove(b)
Art of Multiprocessor Programming© Herlihy-Shavit 2007
d
remove(c)
69
Removing a Node
a
b
c
remove(b)
Art of Multiprocessor Programming© Herlihy-Shavit 2007
d
remove(c)
70
Removing a Node
a
b
c
remove(b)
Art of Multiprocessor Programming© Herlihy-Shavit 2007
d
remove(c)
71
Removing a Node
a
b
c
remove(b)
Art of Multiprocessor Programming© Herlihy-Shavit 2007
d
remove(c)
72
Removing a Node
a
b
c
remove(b)
Art of Multiprocessor Programming© Herlihy-Shavit 2007
d
remove(c)
73
Removing a Node
a
b
d
remove(b)
Art of Multiprocessor Programming© Herlihy-Shavit 2007
74
Removing a Node
a
b
d
remove(b)
Art of Multiprocessor Programming© Herlihy-Shavit 2007
75
Removing a Node
a
b
d
remove(b)
Art of Multiprocessor Programming© Herlihy-Shavit 2007
76
Removing a Node
a
remove(b)
Art of Multiprocessor Programming© Herlihy-Shavit 2007
d
remove(c)
77
Removing a Node
a
Art of Multiprocessor Programming© Herlihy-Shavit 2007
d
78
Remove method
public boolean remove(Item item) {
int key = item.hashCode();
Node pred, curr;
try {
…
} finally {
curr.unlock();
pred.unlock();
}}
Art of Multiprocessor Programming© Herlihy-Shavit 2007
79
Remove method
public boolean remove(Item item) {
int key = item.hashCode();
Node pred, curr;
try {
…
} finally {
curr.unlock();
pred.unlock();
}}
Key used to order node
Art of Multiprocessor Programming© Herlihy-Shavit 2007
80
Remove method
public boolean remove(Item item) {
int key = item.hashCode();
Node pred, curr;
try {
…
} finally {
currNode.unlock();
predNode.unlock();
}}
Predecessor and current nodes
Art of Multiprocessor Programming© Herlihy-Shavit 2007
81
Remove method
public boolean remove(Item item) {
int key = item.hashCode();
Node pred, curr;
try {
Make sure
…
locks released
} finally {
curr.unlock();
pred.unlock();
}}
Art of Multiprocessor Programming© Herlihy-Shavit 2007
82
Remove method
public boolean remove(Item item) {
int key = item.hashCode();
Node pred, curr;
try {
…
} finally {
curr.unlock();
Everything else
pred.unlock();
}}
Art of Multiprocessor Programming© Herlihy-Shavit 2007
83
Remove method
try {
pred = this.head;
pred.lock();
curr = pred.next;
curr.lock();
…
} finally { … }
Art of Multiprocessor Programming© Herlihy-Shavit 2007
84
Remove method
Lock pred == head
try {
pred = this.head;
pred.lock();
curr = pred.next;
curr.lock();
…
} finally { … }
Art of Multiprocessor Programming© Herlihy-Shavit 2007
85
Remove method
try {
pred = this.head;
pred.lock();
curr = pred.next;
curr.lock();
…
} finally { … }
Lock current
Art of Multiprocessor Programming© Herlihy-Shavit 2007
86
Remove method
try {
pred = this.head;
pred.lock();
curr = pred.next;
curr.lock();
…
} finally { … }
Traversing list
Art of Multiprocessor Programming© Herlihy-Shavit 2007
87
Remove: traversing list
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© Herlihy-Shavit 2007
88
Remove: traversing list
while (curr.key <= key) {
if (item == curr.item) {
pred.next = curr.next;
return true;
}
Search key range
pred.unlock();
pred = curr;
curr = curr.next;
curr.lock();
}
return false;
Art of Multiprocessor Programming© Herlihy-Shavit 2007
89
Remove: traversing list
while (curr.key <= key) {
if (item == curr.item) {
pred.next = curr.next;
return true;
}
At start of each loop: curr
pred.unlock();
and pred locked
pred = curr;
curr = curr.next;
curr.lock();
}
return false;
Art of Multiprocessor Programming© Herlihy-Shavit 2007
90
Remove: traversing list
while (curr.key <= key) {
if (item == curr.item) {
pred.next = curr.next;
return true;
}
pred.unlock();
pred = curr;
curr = curr.next;
curr.lock();
}
return
If
item false;
found, remove node
Art of Multiprocessor Programming© Herlihy-Shavit 2007
91
Remove: traversing list
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© Herlihy-Shavit 2007
92
Remove: traversing list
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© Herlihy-Shavit 2007
93
Remove: traversing list
while (curr.key <= key) {
if (item == curr.item) {
demote current
pred.next = curr.next;
return true;
}
pred.unlock();
pred = curr;
curr = curr.next;
curr.lock();
}
return false;
Art of Multiprocessor Programming© Herlihy-Shavit 2007
94
Remove: traversing list
while (curr.key <= key) {
if (item == curr.item) Find
{
and lock
pred.next = curr.next; new current
return true;
}
pred.unlock();
pred = currNode;
curr = curr.next;
curr.lock();
}
return false;
Art of Multiprocessor Programming© Herlihy-Shavit 2007
95
Remove: traversing list
while (curr.key <= key) {
if (item == curr.item) {
Lock invariant
pred.next = curr.next;
restored
return true;
}
pred.unlock();
pred = currNode;
curr = curr.next;
curr.lock();
}
return false;
Art of Multiprocessor Programming© Herlihy-Shavit 2007
96
Remove: traversing list
while (curr.key <= key) {
if (item == curr.item) {
pred.next = curr.next;
return true;
Otherwise, not present
}
pred.unlock();
pred = curr;
curr = curr.next;
curr.lock();
}
return false;
Art of Multiprocessor Programming© Herlihy-Shavit 2007
97
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;
• pred reachable from head
curr.lock();
• curr is pred.next
}
• So curr.item is in the set
return false;
Art of Multiprocessor Programming© Herlihy-Shavit 2007
98
Why remove() is linearizable
while (curr.key <= key) {
if (item == curr.item) {
pred.next = curr.next;
return true;
}
• pred reachable from head
pred.unlock();
• curr is pred.next
pred = curr;
curr = curr.next;• pred.key < key
• key < curr.key
curr.lock();
• So item is not in the set
}
return false;
Art of Multiprocessor Programming© Herlihy-Shavit 2007
99
Why remove() is linearizable
while (curr.key <= key) {
if (item == curr.item) {
pred.next = curr.next;
return true;
}
Linearization point
pred.unlock();
pred = curr;
curr = curr.next;
curr.lock();
}
return false;
Art of Multiprocessor Programming© Herlihy-Shavit 2007
100
Progress
• To avoid deadlock, locks must be
taken by all methods in the same
order
• Starvation freedom (if locks are
starvation free)
Art of Multiprocessor Programming© Herlihy-Shavit 2007
101
Adding Nodes
• To add a node:
– Traverse list using hand-by-hand locking
– Lock predecessor
– Lock successor
• Neither can be deleted
– … and thus item can be inserted inbetween
– (Is successor lock actually required?)
Art of Multiprocessor Programming© Herlihy-Shavit 2007
102
Same Abstraction Map
• S(head) =
– { x | there exists a such that
• a reachable from head and
• a.item = x
–}
Art of Multiprocessor Programming© Herlihy-Shavit 2007
103
Representation Invariant
• Easy to check that
– tail always reachable from head
– Nodes sorted
– No duplicates
Art of Multiprocessor Programming© Herlihy-Shavit 2007
104
Drawbacks
• Better than coarse-grained lock
– Threads can traverse in parallel
• Still not ideal
– Long chain of acquire/release locks
– Inefficient
– Threads working at the beginning of the
list may block other threads
Art of Multiprocessor Programming© Herlihy-Shavit 2007
105
Optimistic Synchronization
• Find nodes without locking
• Lock nodes
• Check that everything is OK
Art of Multiprocessor Programming© Herlihy-Shavit 2007
106
Optimistic: Traverse without
Locking
a
add(c)
b
d
e
Aha!
Art of Multiprocessor Programming© Herlihy-Shavit 2007
107
Optimistic: Lock and Load
a
b
d
e
add(c)
Art of Multiprocessor Programming© Herlihy-Shavit 2007
108
What Can Possibly Go Wrong?
a
add(c)
b
d
e
Aha!
Art of Multiprocessor Programming© Herlihy-Shavit 2007
109
What Can Possibly Go Wrong?
a
b
d
e
add(c)
Art of Multiprocessor Programming© Herlihy-Shavit 2007
110
What Can Possibly Go Wrong?
a
b
d
e
remove(b
)
add(c)
Art of Multiprocessor Programming© Herlihy-Shavit 2007
111
What Can Possibly Go Wrong?
a
b
d
e
add(c)
Art of Multiprocessor Programming© Herlihy-Shavit 2007
112
What Can Possibly Go Wrong?
a
add(c)
b
d
e
c would be added
between b and d,
but b is no more
reachable
(deleted)!
Art of Multiprocessor Programming© Herlihy-Shavit 2007
113
Validate (1)
a
add(c)
b
d
e
Yes, b
still
reachable
from head
Art of Multiprocessor Programming© Herlihy-Shavit 2007
114
What Else Can Go Wrong?
a
add(c)
b
d
e
Aha!
Art of Multiprocessor Programming© Herlihy-Shavit 2007
115
What Else Can Go Wrong?
a
b
d
e
add(c)
Art of Multiprocessor Programming© Herlihy-Shavit 2007
116
What Else Can Go Wrong?
b’
a
b
d
e
add(b’)
add(c)
Art of Multiprocessor Programming© Herlihy-Shavit 2007
117
What Else Can Go Wrong?
b’
a
add(c)
b
d
e
add(b’) invalidated
by add(c)!
Art of Multiprocessor Programming© Herlihy-Shavit 2007
118
Optimistic: Validate(2)
a
add(c)
b
d
e
Yes, b
still points
to d
Art of Multiprocessor Programming© Herlihy-Shavit 2007
119
Optimistic: Linearization Point
a
b
d
e
c
add(c)
Art of Multiprocessor Programming© Herlihy-Shavit 2007
120
Same Abstraction Map
• S(head) =
– { x | there exists a such that
• a reachable from head and
• a.item = x
–}
Art of Multiprocessor Programming© Herlihy-Shavit 2007
121
Invariants
• Careful: we may traverse deleted
nodes
• But we establish properties by
– Validation
– After we lock target nodes
Art of Multiprocessor Programming© Herlihy-Shavit 2007
122
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 add and return true
Art of Multiprocessor Programming© Herlihy-Shavit 2007
123
Removing a Node
a
remove(c
)
b
d
e
Aha!
Art of Multiprocessor Programming© Herlihy-Shavit 2007
124
Validate (1)
a
remove(c
)
b
d
e
Yes, b still
reachable
from head
Art of Multiprocessor Programming© Herlihy-Shavit 2007
125
Validate (2)
a
remove(c
)
b
d
e
Yes, b still
points to d
Art of Multiprocessor Programming© Herlihy-Shavit 2007
126
OK Computer
a
remove(c
)
b
d
e
return false
Art of Multiprocessor Programming© Herlihy-Shavit 2007
127
Correctness
• If
– Nodes b and d both locked
– Node b still accessible
– Node d still successor to b
• Then
– No thread can remove b, d, e
– No thread can add a node between b and d or
between d and e
– OK to remove node or return false
Art of Multiprocessor Programming© Herlihy-Shavit 2007
128
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© Herlihy-Shavit 2007
129
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;
Predecessor &
}
return false;current nodes
}
Art of Multiprocessor Programming© Herlihy-Shavit 2007
130
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;
}
Begin at the
return false;
}
beginning
Art of Multiprocessor Programming© Herlihy-Shavit 2007
131
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;
}
Search range of keys
return false;
}
Art of Multiprocessor Programming© Herlihy-Shavit 2007
132
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© Herlihy-Shavit 2007
133
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;
Is current node next?
}
Art of Multiprocessor Programming© Herlihy-Shavit 2007
134
Validation
private boolean
Otherwise move on
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© Herlihy-Shavit 2007
135
Validation
private boolean Predecessor not reachable
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© Herlihy-Shavit 2007
136
Remove: searching
public boolean remove(Item item) {
int key = item.hashCode();
retry: while (true) {
Node pred = this.head;
Node curr = pred.next;
while (curr.key <= key) {
if (item == curr.item)
break;
pred = curr;
curr = curr.next;
} …
}
Art of Multiprocessor Programming© Herlihy-Shavit 2007
137
Remove: searching
public boolean remove(Item item) {
int key = item.hashCode();
retry: while (true) {
Node pred = this.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© Herlihy-Shavit 2007
138
Remove: searching
public boolean remove(Item item) {
int key = item.hashCode();
retry: while (true) {
Node pred = this.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© Herlihy-Shavit 2007
139
Remove: searching
public boolean remove(Item item) {
int key = item.hashCode();
retry: while (true) {
Node pred = this.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© Herlihy-Shavit 2007
140
Remove: searching
public boolean remove(Item item) {
int key = item.hashCode();
retry: while (true) {
Node pred = this.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© Herlihy-Shavit 2007
141
Remove: searching
public boolean remove(Item item) {
int key = item.hashCode();
retry: while (true) {
Node pred = this.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© Herlihy-Shavit 2007
142
Remove: searching
public boolean remove(Item item) {
Move
int key
= along
item.hashCode();
retry: while (true) {
Node pred = this.head;
Node curr = pred.next;
while (curr.key <= key) {
if (item == curr.item)
break;
pred = curr;
curr = curr.next;
} …
}
Art of Multiprocessor Programming© Herlihy-Shavit 2007
143
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
Art of Multiprocessor Programming© Herlihy-Shavit 2007
144
Remove: details on “…”
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© Herlihy-Shavit 2007
145
Remove: details on “…”
try {
pred.lock(); curr.lock();
if (validate(pred,curr) {
if (curr.item == item) {
pred.next = curr.next;
return true;
} else
return false;
Always unlock
}} finally {
pred.unlock();
curr.unlock();
}
Art of Multiprocessor Programming© Herlihy-Shavit 2007
146
Remove: details on “…”
try {
pred.lock(); curr.lock();
if (validate(pred,curr) {
if (curr.item == item) {
pred.next = curr.next;
return true;
} else
return false;
Lock both nodes
}} finally {
pred.unlock();
curr.unlock();
}
Art of Multiprocessor Programming© Herlihy-Shavit 2007
147
Remove: details on “…”
try {
pred.lock(); curr.lock();
if (validate(pred,curr) {
if (curr.item == item) {
pred.next = curr.next;
return true;
Check for synchronization
} else
return false; conflicts
}} finally {
pred.unlock();
curr.unlock();
}
Art of Multiprocessor Programming© Herlihy-Shavit 2007
148
Remove: details on “…”
try {
pred.lock(); curr.lock();
if (validate(pred,curr) {
if (curr.item == item) {
pred.next = curr.next;
return true;
} else
return false;
target found,
}} finally {
remove node
pred.unlock();
curr.unlock();
}
Art of Multiprocessor Programming© Herlihy-Shavit 2007
149
Remove: details on “…”
try {
pred.lock(); curr.lock();
if (validate(pred,curr) {
if (curr.item == item) {
pred.next = curr.next;
return true;
target not found
} else
return false;
}} finally {
pred.unlock();
curr.unlock();
}
Art of Multiprocessor Programming© Herlihy-Shavit 2007
150
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© Herlihy-Shavit 2007
151
So Far, So Good
• Much less lock acquisition/release
– Performance
– Concurrency
• Problems
– Need to traverse list twice
– contains() method acquires locks
• Most common method call
Art of Multiprocessor Programming© Herlihy-Shavit 2007
152
Evaluation
• Optimistic is effective if
– cost of scanning twice without locks
less than
– cost of scanning once with locks
• Drawback
– contains() acquires locks
– 90% of calls in many apps
Art of Multiprocessor Programming© Herlihy-Shavit 2007
153
Download