Linked Lists: Locking, Lock- Free, and Beyond … Based on the companion slides for The Art of...

Preview:

Citation preview

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

Based on the companion slides forThe Art of Multiprocessor

Programming(Maurice Herlihy & Nir Shavit)

Art of Multiprocessor Programming© Herlihy-Shavit 2007 2

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 3

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 4

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 5

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 6

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 7

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 8

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 9

Linked List

• Illustrate these patterns …• Using a list-based Set

– Common application– Building block for other apps

Art of Multiprocessor Programming© Herlihy-Shavit 2007 10

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 11

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 12

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 13

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 14

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 15

List Node

public class Node { public T item; public int key; public Node next;}

Art of Multiprocessor Programming© Herlihy-Shavit 2007 16

List Node

public class Node { public T item; public int key; public Node next;}

item of interest

Art of Multiprocessor Programming© Herlihy-Shavit 2007 17

List Node

public class Node { public T item; public int key; public Node next;}

Usually hash code

Art of Multiprocessor Programming© Herlihy-Shavit 2007 18

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 19

The List-Based Set

a b c

Sorted with Sentinel nodes(min & max possible keys)

-∞

+∞

Art of Multiprocessor Programming© Herlihy-Shavit 2007 20

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 21

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 22

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 23

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 24

Abstract Data Types

• Concrete representation

• Abstract Type– {a, b}

a b

Art of Multiprocessor Programming© Herlihy-Shavit 2007 25

Abstract Data Types

• Meaning of representation given by abstraction map

– S( ) = {a,b}a b

Art of Multiprocessor Programming© Herlihy-Shavit 2007 26

Abstraction Map

• S(head) ={ x | there exists a such that

a reachable from head anda.item = x

}

Art of Multiprocessor Programming© Herlihy-Shavit 2007 27

Sequential List Based Set

a c d

a b c

Add()

Remove()

Art of Multiprocessor Programming© Herlihy-Shavit 2007 28

Sequential List Based Set

a c d

b

a b c

Add()

Remove()

Art of Multiprocessor Programming© Herlihy-Shavit 2007 29

Sequential List Based Set

a c d

b

a b c

Add()

Remove()

Art of Multiprocessor Programming© Herlihy-Shavit 2007 30

Course Grained Locking

a b d

Art of Multiprocessor Programming© Herlihy-Shavit 2007 31

Course Grained Locking

a b d

c

Art of Multiprocessor Programming© Herlihy-Shavit 2007 32

honk!

Course Grained Locking

a b d

c

Simple but hotspot + bottleneck

honk!

Art of Multiprocessor Programming© Herlihy-Shavit 2007 33

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 34

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

Hand-over-Hand locking

a b c

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 b c d

remove(b)

Art of Multiprocessor Programming© Herlihy-Shavit 2007 45

Removing a Node

a c d

remove(b)

Art of Multiprocessor Programming© Herlihy-Shavit 2007 46

Removing a Node

a b c d

remove(c)remove(

b)

Art of Multiprocessor Programming© Herlihy-Shavit 2007 47

Removing a Node

a b c d

remove(b)

remove(c)

Art of Multiprocessor Programming© Herlihy-Shavit 2007 48

Removing a Node

a b c d

remove(b)

remove(c)

Art of Multiprocessor Programming© Herlihy-Shavit 2007 49

Removing a Node

a b c d

remove(b)

remove(c)

Art of Multiprocessor Programming© Herlihy-Shavit 2007 50

Removing a Node

a b c d

remove(b)

remove(c)

Art of Multiprocessor Programming© Herlihy-Shavit 2007 51

Removing a Node

a b c d

remove(b)

remove(c)

Art of Multiprocessor Programming© Herlihy-Shavit 2007 52

Removing a Node

a b c d

remove(b)

remove(c)

Art of Multiprocessor Programming© Herlihy-Shavit 2007 53

Removing a Node

a b c d

remove(b)

remove(c)

Art of Multiprocessor Programming© Herlihy-Shavit 2007 54

Uh, Oh

a c d

remove(b)

remove(c)

Art of Multiprocessor Programming© Herlihy-Shavit 2007 55

Uh, Oh

a c d

Bad news

remove(b)

remove(c)

Art of Multiprocessor Programming© Herlihy-Shavit 2007 56

Problem• To delete node b

– Swing node a’s next field to c

• Problem is,– Someone could delete c concurrently

ba c

ba c

Art of Multiprocessor Programming© Herlihy-Shavit 2007 57

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

remove(b)

Art of Multiprocessor Programming© Herlihy-Shavit 2007 61

Hand-Over-Hand Again

a b c d

remove(b)

Found it!

Art of Multiprocessor Programming© Herlihy-Shavit 2007 62

Hand-Over-Hand Again

a b c d

remove(b)

Found it!

Art of Multiprocessor Programming© Herlihy-Shavit 2007 63

Hand-Over-Hand Again

a c d

remove(b)

Art of Multiprocessor Programming© Herlihy-Shavit 2007 64

Removing a Node

a b c d

remove(b)

remove(c)

Art of Multiprocessor Programming© Herlihy-Shavit 2007 65

Removing a Node

a b c d

remove(b)

remove(c)

Art of Multiprocessor Programming© Herlihy-Shavit 2007 66

Removing a Node

a b c d

remove(b)

remove(c)

Art of Multiprocessor Programming© Herlihy-Shavit 2007 67

Removing a Node

a b c d

remove(b)

remove(c)

Art of Multiprocessor Programming© Herlihy-Shavit 2007 68

Removing a Node

a b c d

remove(b)

remove(c)

Art of Multiprocessor Programming© Herlihy-Shavit 2007 69

Removing a Node

a b c d

remove(b)

remove(c)

Art of Multiprocessor Programming© Herlihy-Shavit 2007 70

Removing a Node

a b c d

remove(b)

remove(c)

Art of Multiprocessor Programming© Herlihy-Shavit 2007 71

Removing a Node

a b c d

remove(b)

remove(c)

Art of Multiprocessor Programming© Herlihy-Shavit 2007 72

Removing a Node

a b c d

remove(b)

remove(c)

Art of Multiprocessor Programming© Herlihy-Shavit 2007 73

Removing a Node

a b c d

remove(b)

remove(c)

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 b d

remove(b)

Art of Multiprocessor Programming© Herlihy-Shavit 2007 77

Removing a Node

a d

remove(b)

remove(c)

Art of Multiprocessor Programming© Herlihy-Shavit 2007 78

Removing a Node

a d

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(); }}

Art of Multiprocessor Programming© Herlihy-Shavit 2007 80

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 81

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 82

Remove method

public boolean remove(Item item) { int key = item.hashCode(); Node pred, curr; try { … } finally { curr.unlock(); pred.unlock(); }}

Make sure locks

released

Art of Multiprocessor Programming© Herlihy-Shavit 2007 83

Remove method

public boolean remove(Item item) { int key = item.hashCode(); Node pred, curr; try { … } finally { curr.unlock(); pred.unlock(); }}

Everything else

Art of Multiprocessor Programming© Herlihy-Shavit 2007 84

Remove method

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 pred == head

Art of Multiprocessor Programming© Herlihy-Shavit 2007 86

Remove method

try { pred = this.head; pred.lock(); curr = pred.next; curr.lock(); …} finally { … }

Lock current

Art of Multiprocessor Programming© Herlihy-Shavit 2007 87

Remove method

try { pred = this.head; pred.lock(); curr = pred.next; curr.lock(); …} finally { … }

Traversing list

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; } 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; } pred.unlock(); pred = curr; curr = curr.next; curr.lock(); } return false;

Search key range

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 false;

At start of each loop: curr and pred locked

Art of Multiprocessor Programming© Herlihy-Shavit 2007 91

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;If item found, remove

node

Art of Multiprocessor Programming© Herlihy-Shavit 2007 92

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;

Unlock predecessor

Art of Multiprocessor Programming© Herlihy-Shavit 2007 93

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;

Only one node locked!

Art of Multiprocessor Programming© Herlihy-Shavit 2007 94

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;

demote current

Art of Multiprocessor Programming© Herlihy-Shavit 2007 95

Remove: traversing list

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© Herlihy-Shavit 2007 96

Remove: traversing list

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© Herlihy-Shavit 2007 97

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;

Otherwise, not present

Art of Multiprocessor Programming© Herlihy-Shavit 2007 98

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

Art of Multiprocessor Programming© Herlihy-Shavit 2007 99

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• So item is not in the set

Art of Multiprocessor Programming© Herlihy-Shavit 2007 100

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

Art of Multiprocessor Programming© Herlihy-Shavit 2007 101

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 102

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 103

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 104

Representation Invariant

• Easy to check that– tail always reachable from head– Nodes sorted– No duplicates

Art of Multiprocessor Programming© Herlihy-Shavit 2007 105

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 106

Optimistic Synchronization

• Find nodes without locking• Lock nodes• Check that everything is OK

Art of Multiprocessor Programming© Herlihy-Shavit 2007 107

Optimistic: Traverse without Locking

b d ea

add(c)

Aha!

Art of Multiprocessor Programming© Herlihy-Shavit 2007 108

Optimistic: Lock and Load

b d ea

add(c)

Art of Multiprocessor Programming© Herlihy-Shavit 2007 109

What Can Possibly Go Wrong?

b d ea

add(c)

Aha!

Art of Multiprocessor Programming© Herlihy-Shavit 2007 110

What Can Possibly Go Wrong?

b d ea

add(c)

Art of Multiprocessor Programming© Herlihy-Shavit 2007 111

What Can Possibly Go Wrong?

b d ea

add(c)

remove(b)

Art of Multiprocessor Programming© Herlihy-Shavit 2007 112

What Can Possibly Go Wrong?

b d ea

add(c)

Art of Multiprocessor Programming© Herlihy-Shavit 2007 113

What Can Possibly Go Wrong?

b d ea

add(c)

c would be added between b and d, but b is

no more reachable (deleted)!

Art of Multiprocessor Programming© Herlihy-Shavit 2007 114

Validate (1)

b d ea

add(c)

Yes, b still

reachable from head

Art of Multiprocessor Programming© Herlihy-Shavit 2007 115

What Else Can Go Wrong?

b d ea

add(c)

Aha!

Art of Multiprocessor Programming© Herlihy-Shavit 2007 116

What Else Can Go Wrong?

b d ea

add(c)

Art of Multiprocessor Programming© Herlihy-Shavit 2007 117

What Else Can Go Wrong?

b d ea

add(c)

add(b’)

b’

Art of Multiprocessor Programming© Herlihy-Shavit 2007 118

What Else Can Go Wrong?

b d ea

add(c)

b’

add(b’) invalidated by

add( c )!

Art of Multiprocessor Programming© Herlihy-Shavit 2007 119

Optimistic: Validate(2)

b d ea

add(c)

Yes, b still

points to d

Art of Multiprocessor Programming© Herlihy-Shavit 2007 120

Optimistic: Linearization Point

b d ea

add(c)

c

Art of Multiprocessor Programming© Herlihy-Shavit 2007 121

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 122

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 123

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 124

Removing a Node

a b d e

remove(c)

Aha!

Art of Multiprocessor Programming© Herlihy-Shavit 2007 125

Validate (1)

a b d e

Yes, b still reachable from head

remove(c)

Art of Multiprocessor Programming© Herlihy-Shavit 2007 126

Validate (2)

a b d e

remove(c)

Yes, b still points to

d

Art of Multiprocessor Programming© Herlihy-Shavit 2007 127

OK Computer

a b d e

remove(c)

return false

Art of Multiprocessor Programming© Herlihy-Shavit 2007 128

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 129

Validationprivate 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 130

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 & current

nodes

Art of Multiprocessor Programming© Herlihy-Shavit 2007 131

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

Begin at the beginning

Art of Multiprocessor Programming© Herlihy-Shavit 2007 132

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

Search range of keys

Art of Multiprocessor Programming© Herlihy-Shavit 2007 133

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 reachable

Art of Multiprocessor Programming© Herlihy-Shavit 2007 134

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;}

Validation

Is current node next?

Art of Multiprocessor Programming© Herlihy-Shavit 2007 135

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

Art of Multiprocessor Programming© Herlihy-Shavit 2007 136

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;}

ValidationPredecessor not

reachable

Art of Multiprocessor Programming© Herlihy-Shavit 2007 137

Remove: searchingpublic 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 138

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; } … }

Remove: searching

Search key

Art of Multiprocessor Programming© Herlihy-Shavit 2007 139

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; } … }

Remove: searching

Retry on synchronization conflict

Art of Multiprocessor Programming© Herlihy-Shavit 2007 140

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; } … }

Remove: searching

Examine predecessor and current nodes

Art of Multiprocessor Programming© Herlihy-Shavit 2007 141

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; } … }

Remove: searching

Search by key

Art of Multiprocessor Programming© Herlihy-Shavit 2007 142

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; } … }

Remove: searching

Stop if we find item

Art of Multiprocessor Programming© Herlihy-Shavit 2007 143

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; } … }

Remove: searching

Move along

Art of Multiprocessor Programming© Herlihy-Shavit 2007 144

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 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; }} finally {

pred.unlock();curr.unlock();

}

Art of Multiprocessor Programming© Herlihy-Shavit 2007 146

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: details on “…”

Always unlock

Art of Multiprocessor Programming© Herlihy-Shavit 2007 147

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: details on “…”

Lock both nodes

Art of Multiprocessor Programming© Herlihy-Shavit 2007 148

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: details on “…”

Check for synchronization

conflicts

Art of Multiprocessor Programming© Herlihy-Shavit 2007 149

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: details on “…”

target found, remove node

Art of Multiprocessor Programming© Herlihy-Shavit 2007 150

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: details on “…”

target not found

Art of Multiprocessor Programming© Herlihy-Shavit 2007 151

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 152

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 153

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

Recommended