/
Concurrent Queues and Stacks Concurrent Queues and Stacks

Concurrent Queues and Stacks - PowerPoint Presentation

crunchingsubway
crunchingsubway . @crunchingsubway
Follow
343 views
Uploaded On 2020-06-16

Concurrent Queues and Stacks - PPT Presentation

Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy amp Nir Shavit Art of Multiprocessor Programming 2 2 The FiveFold Path Coarsegrained locking Finegrained locking ID: 778985

multiprocessor art node programming art multiprocessor programming node slot public lock tail waiting empty head return heritem enqlock deqlock

Share:

Link:

Embed:

Download Presentation from below link

Download The PPT/PDF document "Concurrent Queues and Stacks" is the property of its rightful owner. Permission is granted to download and print the materials on this web site for personal, non-commercial use only, and to display it on your personal computer provided you do not modify the materials and that you retain all copyright notices contained in the materials. By downloading content from our website, you accept the terms of this agreement.


Presentation Transcript

Slide1

Concurrent Queues and Stacks

Companion slides for

The Art of Multiprocessor Programming

by Maurice Herlihy & Nir Shavit

Slide2

Art of Multiprocessor Programming

2

2

The Five-Fold PathCoarse-grained lockingFine-grained lockingOptimistic synchronization

Lazy synchronizationLock-free synchronization

Slide3

Art of Multiprocessor Programming

3

3

Another Fundamental ProblemWe told you about Sets implemented by linked lists

Hash TablesNext: queuesNext: stacks

Slide4

Art of Multiprocessor Programming

4

4

Queues & Stackspool of items

Slide5

Art of Multiprocessor Programming

5

5

Queues

deq

()/

enq

( )

Total order

First in

First out

Slide6

Art of Multiprocessor Programming

6

6

Stacks

pop()/

push( )

Total order

Last in

First out

Slide7

Art of Multiprocessor Programming

7

7

BoundedFixed capacityGood when resources an issue

Slide8

Art of Multiprocessor Programming

8

8

UnboundedUnlimited capacityOften more convenient

Slide9

Art of Multiprocessor Programming

9

Blocking

zzz

Block on attempt to remove from empty stack or queue

Slide10

Art of Multiprocessor Programming

10

Blocking

zzz

Block on attempt to add to full bounded stack or queue

Slide11

Art of Multiprocessor Programming

11

Non-Blocking

Ouch!

Throw exception on attempt to remove from empty stack or queue

Slide12

Art of Multiprocessor Programming

12

12

This LectureQueueBounded, blocking, lock-basedUnbounded, non-blocking, lock-free

StackUnbounded, non-blocking lock-freeElimination-backoff algorithm

Slide13

Art of Multiprocessor Programming

13

13

Queue: Concurrency

enq(x)

y=deq()

enq()

and

deq()

work at different ends of the object

tail

head

Slide14

Art of Multiprocessor Programming

14

14

Concurrency

enq(x)

Challenge: what if the queue is empty or full?

y=deq()

tail

head

Slide15

Art of Multiprocessor Programming

15

15

Bounded Queue

Sentinel

head

tail

Slide16

Art of Multiprocessor Programming

16

16

Bounded Queue

head

tail

First actual item

Slide17

Art of Multiprocessor Programming

17

17

Bounded Queue

head

tail

Lock out other

deq()

calls

deqLock

Slide18

Art of Multiprocessor Programming

18

18

Bounded Queue

head

tail

Lock out other

enq()

calls

deqLock

enqLock

Slide19

Art of Multiprocessor Programming

19

19

Not Done Yet

head

tail

deqLock

enqLock

Need to tell whether queue is full or empty

Slide20

Art of Multiprocessor Programming

20

20

Not Done Yet

head

tail

deqLock

enqLock

Max size is

8

items

size

1

Slide21

Art of Multiprocessor Programming

21

21

Not Done Yet

head

tail

deqLock

enqLock

Incremented by

enq

()

Decremented by

deq

()

size

1

Slide22

Art of Multiprocessor Programming

22

22

Enqueuer

1

Lock

enqLock

head

tail

deqLock

enqLock

size

Slide23

Art of Multiprocessor Programming

23

23

Enqueuer

1

Read

size

OK

head

tail

deqLock

enqLock

size

Slide24

Art of Multiprocessor Programming

24

24

Enqueuer

1

No need to lock

tail

head

tail

deqLock

enqLock

size

Slide25

Art of Multiprocessor Programming

25

25

Enqueuer

1

Enqueue Node

head

tail

deqLock

enqLock

size

Slide26

Art of Multiprocessor Programming

26

26

Enqueuer

size

1

2

getAndincrement()

head

tail

deqLock

enqLock

Slide27

Art of Multiprocessor Programming

27

27

Enqueuer

8

Release lock

2

head

tail

deqLock

enqLock

size

Slide28

Art of Multiprocessor Programming

28

28

Enqueuer

2

If queue was empty, notify waiting

dequeuers

head

tail

deqLock

enqLock

size

Slide29

Art of Multiprocessor Programming

29

29

Unsuccesful Enqueuer

8

Uh-oh

Read size

head

tail

deqLock

enqLock

size

Slide30

Art of Multiprocessor Programming

30

30

Dequeuer

2

Lock

deqLock

head

tail

deqLock

enqLock

size

Slide31

Art of Multiprocessor Programming

31

31

Dequeuer

2

Read sentinel’s

next

field

OK

head

tail

deqLock

enqLock

size

Slide32

Art of Multiprocessor Programming

32

32

Dequeuer

siz

2

Read

value

head

tail

deqLock

enqLock

size

Slide33

Art of Multiprocessor Programming

33

33

Dequeuer

2

Make first Node new sentinel

head

tail

deqLock

enqLock

size

Slide34

Art of Multiprocessor Programming

34

34

Dequeuer

1

Decrement

size

head

tail

deqLock

enqLock

size

Slide35

Art of Multiprocessor Programming

35

35

Dequeuer

1

Release

deqLock

head

tail

deqLock

enqLock

size

Slide36

Art of Multiprocessor Programming

36

36

Unsuccesful Dequeuer

0

Read sentinel’s

next

field

uh-oh

head

tail

deqLock

enqLock

size

Slide37

Art of Multiprocessor Programming

37

37

Bounded Queue

public class

BoundedQueue

<T> {

ReentrantLock

enqLock

,

deqLock

;

Condition

notEmptyCondition

,

notFullCondition

;

AtomicInteger size; Node head; Node tail; int capacity; enqLock = new ReentrantLock

();

notFullCondition = enqLock.newCondition

();

deqLock = new ReentrantLock(); notEmptyCondition = deqLock.newCondition();}

Slide38

Art of Multiprocessor Programming

38

38

Bounded Queue

public class BoundedQueue

<T> {

ReentrantLock

enqLock

,

deqLock

;

Condition

notEmptyCondition

,

notFullCondition

;

AtomicInteger

size; Node head; Node tail; int capacity; enqLock = new ReentrantLock

();

notFullCondition

=

enqLock.newCondition(); deqLock = new ReentrantLock(); notEmptyCondition = deqLock.newCondition();}

enq & deq locks

Slide39

Art of Multiprocessor Programming

39

(push)

Slide40

Art of Multiprocessor Programming

40

40

Digression: Monitor LocksJava

synchronized objects and ReentrantLocks are monitors

Allow blocking on a condition rather than spinning

Threads:

acquire

and

release

lock

wait

on a condition

Slide41

Art of Multiprocessor Programming

41

41

public interface Lock {

void lock();

void

lockInterruptibly

() throws

InterruptedException

;

boolean

tryLock

();

boolean

tryLock

(long time,

TimeUnit unit); Condition newCondition(); void unlock;}The Java Lock Interface

Acquire lock

Slide42

Art of Multiprocessor Programming

42

42

public interface Lock {

void lock(); void

lockInterruptibly

() throws

InterruptedException

;

boolean

tryLock

();

boolean

tryLock

(long time,

TimeUnit

unit);

Condition newCondition(); void unlock;}The Java Lock Interface

Release lock

Slide43

Art of Multiprocessor Programming

43

43

public interface Lock {

void lock(); void

lockInterruptibly

() throws

InterruptedException

;

boolean

tryLock

();

boolean

tryLock

(

long

time,

TimeUnit unit); Condition newCondition(); void unlock;}The Java Lock Interface

Try for lock, but not too hard

Slide44

Art of Multiprocessor Programming

44

44

public interface Lock {

void lock(); void

lockInterruptibly

() throws

InterruptedException

;

boolean

tryLock

();

boolean

tryLock

(long time,

TimeUnit

unit);

Condition newCondition(); void unlock;}The Java Lock Interface

Create condition to wait on

Slide45

Art of Multiprocessor Programming

45

45

The Java Lock Interface

public interface Lock { void lock();

void

lockInterruptibly

()

throws

InterruptedException

;

boolean

tryLock

();

boolean

tryLock(long time, TimeUnit unit); Condition newCondition(); void unlock;}

Never mind what this method does

Slide46

Art of Multiprocessor Programming

46

46

Lock Conditions

public

interface

Condition {

void

await();

boolean

await(

long

time,

TimeUnit

unit);

void

signal();

void signalAll(); }

Slide47

Art of Multiprocessor Programming

47

47

public interface Condition {

void await();

boolean

await(

long

time,

TimeUnit

unit);

void signal();

void

signalAll

();

}

Lock Conditions

Release lock and

wait on condition

Slide48

Art of Multiprocessor Programming

48

48

public interface Condition {

void await();

boolean

await(long time,

TimeUnit

unit);

void

signal();

void

signalAll

();

}

Lock Conditions

Wake up one waiting thread

Slide49

Art of Multiprocessor Programming

49

49

public interface Condition {

void await();

boolean

await(long time,

TimeUnit

unit);

void signal();

void

signalAll

();

}

Lock Conditions

Wake up all waiting threads

Slide50

Art of Multiprocessor Programming

50

50

AwaitReleases lock associated with

qSleeps (gives up processor)Awakens (resumes running)Reacquires lock & returns

q.await

()

Slide51

Art of Multiprocessor Programming

51

51

SignalAwakens one waiting thread

Which will reacquire lock

q.signal

();

Slide52

Art of Multiprocessor Programming

52

52

Signal AllAwakens all

waiting threadsWhich will each reacquire lock

q.signalAll

();

Slide53

Art of Multiprocessor Programming

53

53

A Monitor Lock

Critical Section

waiting room

lock

()

unlock

()

Slide54

Art of Multiprocessor Programming

54

54

Unsuccessful Deq

Critical Section

waiting room

lock

()

await()

deq

()

Oh no,

empty

!

Slide55

Art of Multiprocessor Programming

55

55

Another One

Critical Section

waiting room

lock

()

await()

deq

()

Oh no,

empty

!

Slide56

Art of Multiprocessor Programming

56

56

Enqueuer to the Rescue

Critical Section

waiting room

lock

()

signalAll

()

enq

( )

unlock

()

Yawn!

Yawn!

Slide57

Art of Multiprocessor Programming

57

57

Yawn!

Monitor Signalling

Critical Section

waiting room

Yawn!

Awakened thread

might still lose lock to

outside contender…

Slide58

Art of Multiprocessor Programming

58

58

Dequeuers Signalled

Critical Section

waiting room

Found it

Yawn!

Slide59

Art of Multiprocessor Programming

59

59

Yawn!

Dequeuers Signaled

Critical Section

waiting room

Still empty!

Slide60

Art of Multiprocessor Programming

60

60

Dollar Short + Day Late

Critical Section

waiting room

Slide61

Art of Multiprocessor Programming

61

61

public class

Queue<T> {

int

head = 0, tail = 0;

T[QSIZE] items;

public synchronized T

deq

() {

while

(tail – head == 0)

wait();

T result = items[head % QSIZE]; head++;

notifyAll

();

return result; } …}}Java Synchronized Methods

Slide62

Art of Multiprocessor Programming

62

62

public class

Queue<T> {

int

head = 0, tail = 0;

T[QSIZE] items;

public synchronized T

deq

() {

while (tail – head == 0)

wait();

T result = items[head % QSIZE]; head++;

notifyAll

();

return result;

}

}}Java Synchronized Methods

Each object has an implicit lock with an implicit condition

Slide63

Art of Multiprocessor Programming

63

63

public class Queue<T> {

int

head = 0, tail = 0;

T[QSIZE] items;

public

synchronized

T

deq

() {

while (tail – head == 0)

wait();

T result = items[head % QSIZE]; head++;

notifyAll

();

return result;

}

…}}Java Synchronized Methods

Lock on entry, unlock on return

Slide64

Art of Multiprocessor Programming

64

64

public class Queue<T> {

int

head = 0, tail = 0;

T[QSIZE] items;

public synchronized T

deq

() {

while (tail – head == 0)

wait();

T result = items[head % QSIZE]; head++;

this.notifyAll

();

return result;

}

}}Java Synchronized Methods

Wait on implicit condition

Slide65

Art of Multiprocessor Programming

65

65

public class Queue<T> {

int

head = 0, tail = 0;

T[QSIZE] items;

public synchronized T

deq

() {

while (tail – head == 0)

this.wait

();

T result = items[head % QSIZE]; head++;

notifyAll

();

return result;

} …}}Java Synchronized Methods

Signal all threads waiting on condition

Slide66

Art of Multiprocessor Programming

66

66

(Pop!) The Bounded Queue

public class

BoundedQueue

<T> {

ReentrantLock

enqLock

,

deqLock

;

Condition

notEmptyCondition

,

notFullCondition

;

AtomicInteger size; Node head; Node tail; int capacity; enqLock = new ReentrantLock

();

notFullCondition = enqLock.newCondition

();

deqLock = new ReentrantLock(); notEmptyCondition = deqLock.newCondition();}

Slide67

Art of Multiprocessor Programming

67

67

Bounded Queue Fields

public class BoundedQueue

<T> {

ReentrantLock

enqLock

,

deqLock

;

Condition

notEmptyCondition

,

notFullCondition

;

AtomicInteger

size; Node head; Node tail; int capacity; enqLock = new ReentrantLock

();

notFullCondition

=

enqLock.newCondition(); deqLock = new ReentrantLock(); notEmptyCondition = deqLock.newCondition();}

Enq & deq locks

Slide68

Art of Multiprocessor Programming

68

68

Bounded Queue Fields

public class BoundedQueue

<T> {

ReentrantLock

enqLock

,

deqLock

;

Condition

notEmptyCondition

,

notFullCondition

;

AtomicInteger

size; Node head; Node tail; int capacity; enqLock

= new

ReentrantLock();

notFullCondition

= enqLock.newCondition(); deqLock = new ReentrantLock(); notEmptyCondition = deqLock.newCondition();}

Enq lock’s associated condition

Slide69

Art of Multiprocessor Programming

69

69

Bounded Queue Fields

public class BoundedQueue

<T> {

ReentrantLock

enqLock

,

deqLock

;

Condition

notEmptyCondition

,

notFullCondition

;

AtomicInteger

size; Node head; Node tail; int capacity; enqLock = new

ReentrantLock

();

notFullCondition

= enqLock.newCondition(); deqLock = new ReentrantLock(); notEmptyCondition = deqLock.newCondition();}

size: 0 to capacity

Slide70

Art of Multiprocessor Programming

70

70

Bounded Queue Fields

public class BoundedQueue

<T> {

ReentrantLock

enqLock

,

deqLock

;

Condition

notEmptyCondition

,

notFullCondition

;

AtomicInteger

size; Node head; Node tail; int capacity;

enqLock

= new ReentrantLock();

notFullCondition = enqLock.newCondition(); deqLock = new ReentrantLock(); notEmptyCondition = deqLock.newCondition

();}Head and Tail

Slide71

Art of Multiprocessor Programming

71

71

Enq Method Part One

public void

enq

(T x) {

boolean

mustWakeDequeuers

=

false

;

enqLock.lock

();

try

{

while (size.get() == Capacity) notFullCondition.await(); Node e = new Node(x); tail.next = e; tail =

tail.next

; if (

size.getAndIncrement

() == 0) mustWakeDequeuers = true; } finally { enqLock.unlock(); } …}

Slide72

Art of Multiprocessor Programming

72

72

public void

enq(T x) {

boolean

mustWakeDequeuers

= false;

enqLock.lock

();

try {

while (

size.get

() == capacity)

notFullCondition.await

();

Node e = new Node(x); tail.next = e; tail = tail.next; if (size.getAndIncrement

() == 0)

mustWakeDequeuers = true;

}

finally { enqLock.unlock(); } …}Enq Method Part OneLock and unlock enq

lock

Slide73

Art of Multiprocessor Programming

73

73

public void

enq(T x) {

boolean

mustWakeDequeuers

= false;

enqLock.lock

();

try {

while

(

size.get

() == capacity)

notFullCondition.await

(); Node e = new Node(x); tail.next = e; tail = tail.next; if (

size.getAndIncrement

() == 0) mustWakeDequeuers

= true;

} finally { enqLock.unlock(); } …}Enq Method Part OneWait while queue is full …

Slide74

Art of Multiprocessor Programming

74

74

public void

enq(T x) {

boolean

mustWakeDequeuers

= false;

enqLock.lock

();

try {

while

(

size.get

() == capacity)

notFullCondition.await

(); Node e = new Node(x); tail.next = e; tail = tail.next; if (

size.getAndIncrement

() == 0) mustWakeDequeuers

= true;

} finally { enqLock.unlock(); } …}Enq Method Part Onewhen await()

returns, you might still fail the test !

Slide75

Art of Multiprocessor Programming

75

75

public void

enq(T x) {

boolean

mustWakeDequeuers

= false;

enqLock.lock

();

try {

while

(

size.get

() == capacity)

notFullCondition.await

(); Node e = new Node(x); tail.next = e; tail = tail.next; if (

size.getAndIncrement

() == 0) mustWakeDequeuers

= true;

} finally { enqLock.unlock(); } …}Be AfraidAfter the loop: how do we know the queue won’t become full again?

Slide76

Art of Multiprocessor Programming

76

76

public void

enq(T x) {

boolean

mustWakeDequeuers

= false;

enqLock.lock

();

try {

while (

size.get

() == capacity)

notFullCondition.await

();

Node e = new Node(x); tail.next = e; tail = tail.next; if (

size.getAndIncrement

() == 0)

mustWakeDequeuers

= true; } finally { enqLock.unlock(); } …}Enq Method Part OneAdd new node

Slide77

Art of Multiprocessor Programming

77

77

public void

enq(T x) {

boolean

mustWakeDequeuers

= false;

enqLock.lock

();

try {

while (

size.get

() == capacity)

notFullCondition.await

();

Node e = new Node(x);

tail.next = e; tail = tail.next; if (size.getAndIncrement

() == 0)

mustWakeDequeuers =

true

; } finally { enqLock.unlock(); } …}Enq Method Part OneIf queue was empty, wake frustrated

dequeuers

Slide78

Art of Multiprocessor Programming

78

78

Beware Lost Wake-Ups

Critical Section

waiting room

lock

()

Queue empty so signal

()

enq

( )

unlock

()

Yawn!

Slide79

Art of Multiprocessor Programming

79

79

Lost Wake-Up

Critical Section

waiting room

lock

()

enq

(

)

unlock

()

Yawn!

Queue not empty so no need to signal

Slide80

Art of Multiprocessor Programming

80

80

Lost Wake-Up

Critical Section

waiting room

Yawn!

Slide81

Art of Multiprocessor Programming

81

81

Lost Wake-Up

Critical Section

waiting room

Found it

Slide82

Art of Multiprocessor Programming

82

82

What’s Wrong Here?

Critical Section

waiting room

Still waiting ….!

Slide83

Art of Multiprocessor Programming

83

Solution to Lost Wakeup Always use

signalAll() and notifyAll() Not

signal() and notify()

83

Slide84

Art of Multiprocessor Programming

84

(pop)

Slide85

Art of Multiprocessor Programming

85

85

Enq Method Part Deux

public

void

enq

(T x) {

if

(

mustWakeDequeuers

) {

deqLock.lock

();

try

{

notEmptyCondition.signalAll(); } finally { deqLock.unlock(); } } }

Slide86

Art of Multiprocessor Programming

86

86

Enq Method Part Deux

public void enq

(T x) {

if

(

mustWakeDequeuers

) {

deqLock.lock

();

try {

notEmptyCondition.signalAll

();

} finally {

deqLock.unlock(); } } }Are there dequeuers

to be signaled?

Slide87

Art of Multiprocessor Programming

87

87

public void

enq(T x) {

if (

mustWakeDequeuers

) {

deqLock.lock

();

try {

notEmptyCondition.signalAll

();

} finally {

deqLock.unlock

();

} } }Enq Method Part DeuxLock and unlock deq

lock

Slide88

Art of Multiprocessor Programming

88

88

public void

enq(T x) {

if (

mustWakeDequeuers

) {

deqLock.lock

();

try {

notEmptyCondition.signalAll

();

} finally {

deqLock.unlock

(); } } }Enq Method Part DeuxSignal dequeuers

that queue is no longer empty

Slide89

Art of Multiprocessor Programming

89

89

The enq() &

deq() Methods

Share no locks

That’s good

But do share an atomic counter

Accessed on every method call

That’s not so good

Can we alleviate this bottleneck?

Slide90

Art of Multiprocessor Programming

90

90

Split the CounterThe enq() method

Increments onlyCares only if value is capacityThe deq() methodDecrements only

Cares only if value is

zero

Slide91

Art of Multiprocessor Programming

91

91

Split CounterEnqueuer increments

enqSizeDequeuer increments

deqSize

When

enqueuer

hits capacity

Locks

deqLock

Sets

size =

enqSize

-

DeqSize

Intermittent synchronization

Not with each method call

Need both locks! (careful …)

Slide92

Art of Multiprocessor Programming

92

92

A Lock-Free Queue

Sentinel

head

tail

Slide93

Art of Multiprocessor Programming

93

93

Compare and Set

CAS

Slide94

Art of Multiprocessor Programming

94

94

Enqueue

head

tail

enq

( )

Slide95

Art of Multiprocessor Programming

95

95

Enqueue

head

tail

Slide96

Art of Multiprocessor Programming

96

96

Logical Enqueue

head

tail

CAS

Slide97

Art of Multiprocessor Programming

97

97

Physical Enqueue

head

tail

CAS

Slide98

Art of Multiprocessor Programming

98

98

EnqueueThese two steps are not atomicThe

tail field refers to eitherActual last Node (good)Penultimate Node (not so good)Be prepared!

Slide99

Art of Multiprocessor Programming

99

99

EnqueueWhat do you do if you findA trailing tail

?Stop and help fix itIf tail node has non-null next field

CAS the queue’s

tail

field to

tail.next

As in the universal construction

Slide100

Art of Multiprocessor Programming

100

100

When CASs FailDuring logical enqueue

Abandon hope, restartStill lock-free (why?)During physical enqueueIgnore it (why?)

Slide101

Art of Multiprocessor Programming

101

101

Dequeuer

head

tail

Read value

Slide102

Art of Multiprocessor Programming

102

102

Dequeuer

head

tail

Make first Node new sentinel

CAS

Slide103

Art of Multiprocessor Programming

103

103

Memory Reuse?What do we do with nodes after we dequeue them?Java: let garbage collector deal?Suppose there is no GC, or we prefer not to use it?

Slide104

Art of Multiprocessor Programming

104

104

Dequeuer

head

tail

CAS

Can recycle

Slide105

Art of Multiprocessor Programming

105

105

Simple SolutionEach thread has a free list of unused queue nodesAllocate node:

pop from listFree node: push onto listDeal with underflow somehow …

Slide106

Art of Multiprocessor Programming

106

106

Why Recycling is Hard

Free pool

head

tail

Want to redirect head from

gray

to red

zzz…

Slide107

Art of Multiprocessor Programming

107

107

Both Nodes Reclaimed

Free pool

zzz

head

tail

Slide108

Art of Multiprocessor Programming

108

108

One Node Recycled

Free pool

Yawn!

head

tail

Slide109

Art of Multiprocessor Programming

109

109

Why Recycling is Hard

Free pool

CAS

head

tail

OK, here I go!

Slide110

Art of Multiprocessor Programming

110

110

Recycle FAIL

Free pool

zOMG what went wrong?

head

tail

Slide111

Art of Multiprocessor Programming

111

111

The Dreaded ABA Problem

head

tail

Head reference has value

A

Thread reads value

A

Slide112

Art of Multiprocessor Programming

112

112

Dreaded ABA continued

zzz

head

tail

Head reference has value

B

Node

A

freed

Slide113

Art of Multiprocessor Programming

113

113

Dreaded ABA continued

Yawn!

head

tail

Head reference has value

A

again

Node

A

recycled and reinitialized

Slide114

Art of Multiprocessor Programming

114

114

Dreaded ABA continued

CAS

head

tail

CAS succeeds because references match,

even though reference’s meaning has changed

Slide115

Art of Multiprocessor Programming

115

115

The Dreaded ABA FAILIs a result of CAS() semanticsOracle, Intel, AMD, …Not with Load-Locked/Store-Conditional

IBM …

Slide116

Art of Multiprocessor Programming

116

116

Dreaded ABA – A SolutionTag each pointer with a counterUnique over lifetime of nodePointer size vs word size issues

Overflow?Don’t worry be happy?Bounded tags?AtomicStampedReference class

Slide117

Art of Multiprocessor Programming

117

117

Atomic Stamped Reference

AtomicStampedReference

class

Java.util.concurrent.atomic

package

address

S

Stamp

Reference

Can get reference & stamp atomically

Slide118

Art of Multiprocessor Programming

118

118

Concurrent StackMethodspush(x)

pop()Last-in, First-out (LIFO) orderLock-Free!

Slide119

Art of Multiprocessor Programming

119

119

Empty Stack

Top

Slide120

Art of Multiprocessor Programming

120

120

Push

Top

Slide121

Art of Multiprocessor Programming

121

121

Push

Top

CAS

Slide122

Art of Multiprocessor Programming

122

122

Push

Top

Slide123

Art of Multiprocessor Programming

123

123

Push

Top

Slide124

Art of Multiprocessor Programming

124

124

Push

Top

Slide125

Art of Multiprocessor Programming

125

125

Push

Top

CAS

Slide126

Art of Multiprocessor Programming

126

126

Push

Top

Slide127

Art of Multiprocessor Programming

127

127

Pop

Top

Slide128

Art of Multiprocessor Programming

128

128

Pop

Top

CAS

Slide129

Art of Multiprocessor Programming

129

129

Pop

Top

CAS

mine!

Slide130

Art of Multiprocessor Programming

130

130

Pop

Top

CAS

Slide131

Art of Multiprocessor Programming

131

131

Pop

Top

Slide132

Art of Multiprocessor Programming

132

132

public class

LockFreeStack {

private

AtomicReference

top =

new

AtomicReference

(

null

);

public

boolean

tryPush

(Node node){ Node oldTop = top.get(); node.next = oldTop; return(

top.compareAndSet

(oldTop, node))

}

public void push(T value) { Node node = new Node(value); while (true) { if (tryPush(node)) {

return; } else backoff.backoff(); }}

Lock-free Stack

Slide133

Art of Multiprocessor Programming

133

133

public class

LockFreeStack {

private

AtomicReference

top = new

AtomicReference

(null);

public Boolean

tryPush

(Node node){

Node

oldTop

=

top.get

();

node.next = oldTop; return(top.compareAndSet

(

oldTop, node))

}

public void push(T value) { Node node = new Node(value); while (true) { if (tryPush(node)) { return; } else backoff.backoff()}}

Lock-free StacktryPush attempts to push a node

Slide134

Art of Multiprocessor Programming

134

134

public class

LockFreeStack {

private

AtomicReference

top = new

AtomicReference

(null);

public

boolean

tryPush

(Node node){

Node

oldTop

=

top.get

();

node.next = oldTop; return(top.compareAndSet(

oldTop

, node)) }

public void push(T value) {

Node node = new Node(value); while (true) { if (tryPush(node)) { return; } else backoff.backoff()}}

Lock-free StackRead top value

Slide135

Art of Multiprocessor Programming

135

135

public class

LockFreeStack {

private

AtomicReference

top = new

AtomicReference

(null);

public

boolean

tryPush

(Node node){

Node

oldTop

=

top.get

();

node.next = oldTop; return

(top.compareAndSet

(oldTop

, node))

} public void push(T value) { Node node = new Node(value); while (true) { if (tryPush(node)) { return; } else backoff.backoff()

}} Lock-free Stack

current top will be new node’s successor

Slide136

Art of Multiprocessor Programming

136

136

public class

LockFreeStack {

private

AtomicReference

top = new

AtomicReference

(null);

public

boolean

tryPush

(Node node){

Node

oldTop

=

top.get

();

node.next = oldTop; return(top.compareAndSet

(

oldTop, node)) }

public void push(T value) {

Node node = new Node(value); while (true) { if (tryPush(node)) { return; } else backoff.backoff()}}

Lock-free StackTry to swing top, return success or failure

Slide137

Art of Multiprocessor Programming

137

137

public class

LockFreeStack {

private

AtomicReference

top = new

AtomicReference

(null);

public

boolean

tryPush

(Node node){

Node

oldTop

=

top.get

();

node.next = oldTop; return(

top.compareAndSet

(oldTop, node))

}

public void push(T value) { Node node = new Node(value); while (true) { if (tryPush(node)) { return; } else backoff.backoff

()}} Lock-free StackPush calls tryPush

Slide138

Art of Multiprocessor Programming

138

138

public class

LockFreeStack {

private

AtomicReference

top = new

AtomicReference

(null);

public

boolean

tryPush

(Node node){

Node

oldTop

=

top.get

();

node.next = oldTop; return

(

top.compareAndSet(oldTop

, node))

} public void push(T value) { Node node = new Node(value); while (true) { if (tryPush(node)) { return; } else backoff.backoff

()}} Lock-free StackCreate new node

Slide139

Art of Multiprocessor Programming

139

139

public class

LockFreeStack {

private

AtomicReference

top = new

AtomicReference

(null);

public

boolean

tryPush

(Node node){

Node

oldTop

=

top.get

();

node.next = oldTop; return

(

top.compareAndSet(oldTop

, node))

} public void push(T value) { Node node = new Node(value); while (true) { if (tryPush(node)) {

return; } else backoff.backoff()}} Lock-free Stack

If tryPush() fails,back off before retrying

Slide140

Art of Multiprocessor Programming

140

140

Lock-free StackGoodNo locking

BadWithout GC, fear ABAWithout backoff, huge contention at top In any case, no parallelism

Slide141

Art of Multiprocessor Programming

141

141

Big QuestionAre stacks inherently sequential?

Reasons whyEvery pop() call fights for top itemReasons why notStay tuned …

Slide142

Art of Multiprocessor Programming

142

142

Elimination-Backoff StackHow to“turn contention into parallelism”Replace familiar

exponential backoff With alternativeelimination-backoff

Slide143

Art of Multiprocessor Programming

143

143

Observation

Push( )

Pop()

linearizable stack

After an equal number

of pushes and pops,

stack stays the same

Yes!

Slide144

Art of Multiprocessor Programming

144

144

Idea: Elimination Array

Push( )

Pop()

stack

Pick at

random

Pick at

random

Elimination

Array

Slide145

Art of Multiprocessor Programming

145

145

Push Collides With Pop

Push( )

Pop()

stack

continue

continue

No need to

access stack

Yes!

Slide146

Art of Multiprocessor Programming

146

146

No Collision

Push( )

Pop()

stack

If no collision,

access stack

If pushes collide or pops collide access stack

Slide147

Art of Multiprocessor Programming

147

147

Elimination-Backoff StackLock-free stack + elimination arrayAccess Lock-free stack, If

uncontended, apply operation if contended, back off to elimination array and attempt elimination

Slide148

Art of Multiprocessor Programming

148

148

Elimination-Backoff Stack

Push( )

Pop()

Top

CAS

If CAS fails, back off

Slide149

Art of Multiprocessor Programming

149

149

Dynamic Range and Delay

Push( )

Pick random range and max waiting time based on level of contention encountered

Slide150

50-50, Random Slots

0

20000

40000

60000

80000

100000

120000

2

4

8

1

21

62

4

3

24

04

85

66

4

Th

r

e

a

d

s

o

p

s

/

m

s

e

c

E

x

ch

an

ger

T

r

ei

ber

Slide151

Asymmetric

Rendevous

pop

1

(

)

pop

2

(

)

Push( )

Pops find first vacant slot and spin. Pushes hunt for pops.

15

94

26

head:

Slide152

Asymmetric vs. Symmetric

Slide153

Slide154

Effect of

Backoff

and Slot Choice

Slide155

Effect of Slot Choice

Random choice Sequential choice

Darker shades mean more exchanges

Slide156

Effect of Slot Choice

Slide157

Art of Multiprocessor Programming

157

157

Linearizability

Un-eliminated callslinearized as beforeEliminated calls:linearize pop()

immediately after

matching

push()

Combination

is a

linearizable

stack

Slide158

Art of Multiprocessor Programming

158

158

Un-Eliminated Linearizability

push(v1

)

time

time

linearizable

push(v

1

)

pop(v

1

)

pop(v

1

)

Slide159

Art of Multiprocessor Programming

159

159

Eliminated Linearizability

pop(v2

)

push(v

1

)

push(v

2

)

time

time

push(v

2

)

pop(v

2

)

push(v

1

)

pop(v

1

)

Collision

Point

Red calls are

eliminated

pop(v

1)linearizable

Slide160

Art of Multiprocessor Programming

160

160

Backoff Has Dual EffectElimination introduces parallelismBackoff to array cuts contention on lock-free stackElimination in array cuts down number of threads accessing lock-free stack

Slide161

Art of Multiprocessor Programming

161

161

public class

EliminationArray {

private static final

int

duration = ...;

private static final

int

timeUnit

= ...;

Exchanger<T>[] exchanger;

public

EliminationArray

(

int

capacity) { exchanger = new Exchanger[capacity]; for (int i = 0; i < capacity; i++)

exchanger[

i] = new

Exchanger<T>();

… } …}Elimination Array

Slide162

Art of Multiprocessor Programming

162

162

public class

EliminationArray { private static final

int

duration = ...;

private static final

int

timeUnit

= ...;

Exchanger<T>[] exchanger;

public

EliminationArray

(

int

capacity) {

exchanger =

new

Exchanger[capacity];

for (int i = 0; i < capacity; i++)

exchanger[i

] = new Exchanger<T>();

… } …}Elimination ArrayAn array of Exchangers

Slide163

Art of Multiprocessor Programming

163

163

public class

Exchanger<T> { AtomicStampedReference

<T> slot

=

new

AtomicStampedReference

<T>(

null

, 0);

Digression: A Lock-Free Exchanger

Slide164

Art of Multiprocessor Programming

164

164

public class Exchanger<T> {

AtomicStampedReference<T> slot

= new

AtomicStampedReference

<T>(null, 0);

A Lock-Free Exchanger

Atomically modifiable reference + status

Slide165

Art of Multiprocessor Programming

165

165

Atomic Stamped ReferenceAtomicStampedReference class

Java.util.concurrent.atomic packageIn C or C++

:

address

S

reference

stamp

Slide166

Art of Multiprocessor Programming

166

166

Extracting Reference & Stamp

public

T get(

int

[]

stampHolder

);

Slide167

Art of Multiprocessor Programming

167

167

Extracting Reference & Stamp

public

T

get(

int

[]

stampHolder

);

Returns reference to object of type T

Returns stamp at array index 0!

Slide168

Art of Multiprocessor Programming

168

168

Exchanger Status

enum Status {EMPTY, WAITING, BUSY};

Slide169

Art of Multiprocessor Programming

169

169

Exchanger Status

enum Status {

EMPTY

, WAITING, BUSY};

Nothing yet

Slide170

enum

Status {

EMPTY, WAITING, BUSY};

Art of Multiprocessor Programming

170

170

Exchange Status

Nothing yet

One thread is waiting for

rendez-vous

Slide171

Art of Multiprocessor Programming

171

171

Exchange Status

enum Status {

EMPTY, WAITING, BUSY};

Nothing yet

One thread is waiting for

rendez-vous

Other threads busy with

rendez-vous

Slide172

Art of Multiprocessor Programming

172

172

public

T Exchange(T myItem,

long

nanos

)

throws

TimeoutException

{

long

timeBound

=

System.nanoTime

() +

nanos

; int[] stampHolder = {EMPTY}; while (true) { if

(

System.nanoTime() > timeBound

)

throw new TimeoutException(); T herItem = slot.get(stampHolder); int stamp = stampHolder

[0]; switch(stamp) { case EMPTY: … // slot is free case WAITING: …

// someone waiting for me case BUSY: … // others exchanging } }The Exchange

Slide173

Art of Multiprocessor Programming

173

173

public

T Exchange(T myItem,

long

nanos

)

throws

TimeoutException

{

long

timeBound

=

System.nanoTime

() +

nanos

; int[] stampHolder = {EMPTY}; while (true) { if (System.nanoTime() >

timeBound

) throw new TimeoutException

();

T herItem = slot.get(stampHolder); int stamp = stampHolder[0]; switch(stamp) {

case EMPTY: … // slot is free case WAITING: … // someone waiting for me case BUSY: … // others exchanging } }The Exchange

Item and timeout

Slide174

Art of Multiprocessor Programming

174

174

public T Exchange(T

myItem, long

nanos

)

throws

TimeoutException

{

long

timeBound

=

System.nanoTime

() +

nanos

;

int

[]

stampHolder = {EMPTY}; while (true) { if (System.nanoTime() > timeBound) throw new

TimeoutException

(); T

herItem

= slot.get(stampHolder); int stamp = stampHolder[0]; switch(stamp) { case EMPTY: … // slot is free case WAITING: … // someone waiting for me

case BUSY: … // others exchanging } }The Exchange

Array holds status

Slide175

Art of Multiprocessor Programming

175

175

public T Exchange(T

myItem, long

nanos

) throws

TimeoutException

{

long

timeBound

=

System.nanoTime

() +

nanos

;

int

[]

stampHolder

= {0};

while (true) { if (System.nanoTime() > timeBound

)

throw

new

TimeoutException(); T herItem = slot.get(stampHolder); int stamp = stampHolder

[0]; switch(stamp) { case EMPTY: // slot is free case WAITING: // someone waiting for me case BUSY: // others exchanging } }}The Exchange

Loop until timeout

Slide176

Art of Multiprocessor Programming

176

176

public T Exchange(T

myItem, long

nanos

) throws

TimeoutException

{

long

timeBound

=

System.nanoTime

() +

nanos

;

int

[]

stampHolder

= {0};

while (true) { if (System.nanoTime() > timeBound) throw new TimeoutException();

T herItem =

slot.get

(stampHolder); int stamp = stampHolder[0]; switch(stamp) { case EMPTY: // slot is free case WAITING: // someone waiting for me case BUSY: // others exchanging } }}

The ExchangeGet other’s item and status

Slide177

Art of Multiprocessor Programming

177

177

public T Exchange(T

myItem, long

nanos

) throws

TimeoutException

{

long

timeBound

=

System.nanoTime

() +

nanos

;

int

[]

stampHolder

= {0};

while (true) { if (System.nanoTime() > timeBound) throw new TimeoutException();

T

herItem =

slot.get

(stampHolder); int stamp = stampHolder[0]; switch(stamp) { case EMPTY: … // slot is free

case WAITING: … // someone waiting for me case BUSY: … // others exchanging } }}

The ExchangeAn Exchanger has three possible states

Slide178

Art of Multiprocessor Programming

178

178

Lock-free Exchanger

EMPTY

Slide179

Art of Multiprocessor Programming

179

179

EMPTY

Lock-free Exchanger

CAS

Slide180

Art of Multiprocessor Programming

180

180

WAITING

Lock-free Exchanger

Slide181

Art of Multiprocessor Programming

181

181

Lock-free Exchanger

In search of partner …

WAITING

Slide182

Art of Multiprocessor Programming

182

182

WAITING

Lock-free Exchanger

Slot

Still waiting …

Try to exchange item and set status to

BUSY

CAS

Slide183

Art of Multiprocessor Programming

183

183

BUSY

Lock-free Exchanger

Slot

Partner showed up, take item and reset to

EMPTY

item

status

Slide184

Art of Multiprocessor Programming

184

184

EMPTY

BUSY

Lock-free Exchanger

Slot

item

status

Partner showed up, take item and reset to

EMPTY

Slide185

Art of Multiprocessor Programming

185

185

case EMPTY:

// slot is free

if

(

slot.CAS

(

herItem

,

myItem

, EMPTY, WAITING)) {

while

(

System.nanoTime

() <

timeBound

){

herItem = slot.get(stampHolder); if (stampHolder[0] == BUSY) { slot.set(null, EMPTY);

return

herItem;

}}

if (slot.CAS(myItem, null, WAITING, EMPTY)){ throw new TimeoutException(); } else

{ herItem = slot.get(stampHolder); slot.set(null

, EMPTY); return herItem; }} break; Exchanger State EMPTY

Slide186

Art of Multiprocessor Programming

186

186

case EMPTY: // slot is free

if (slot.CAS(herItem

,

myItem

, EMPTY, WAITING)) {

while (

System.nanoTime

() <

timeBound

){

herItem

=

slot.get

(

stampHolder

);

if (stampHolder[0] == BUSY) { slot.set(null, EMPTY); return herItem;

}}

if (slot.CAS(myItem

, null, WAITING, EMPTY)){

throw new TimeoutException(); } else { herItem = slot.get(stampHolder); slot.set(null, EMPTY);

return herItem; }} break; Exchanger State EMPTY

Try to insert myItem and change state to WAITING

Slide187

Art of Multiprocessor Programming

187

187

case EMPTY: // slot is free

if (slot.CAS(herItem

,

myItem

, EMPTY, WAITING)) {

while

(

System.nanoTime

() <

timeBound

){

herItem

=

slot.get

(

stampHolder

); if (stampHolder[0] == BUSY) { slot.set(null, EMPTY); return herItem

;

}} if (slot.CAS(

myItem, null, WAITING, EMPTY)){

throw new TimeoutException(); } else { herItem = slot.get(stampHolder);

slot.set(null, EMPTY); return herItem; }} break; Exchanger State EMPTY

Spin until either myItem is taken or timeout

Slide188

Art of Multiprocessor Programming

188

188

case EMPTY: // slot is free

if (slot.CAS(herItem

,

myItem

, EMPTY, WAITING)) {

while (

System.nanoTime

() <

timeBound

){

herItem

=

slot.get

(

stampHolder

);

if (stampHolder[0] == BUSY) { slot.set(null, EMPTY);

return

herItem;

}}

if (slot.CAS(myItem, null, WAITING, EMPTY)){ throw new TimeoutException(); } else { herItem = slot.get(stampHolder

); slot.set(null, EMPTY); return herItem; }} break;

Exchanger State EMPTYmyItem was taken, so return herItem

that was put in its place

Slide189

Art of Multiprocessor Programming

189

189

case EMPTY: // slot is free

if (slot.CAS(herItem

,

myItem

, EMPTY, WAITING)) {

while (

System.nanoTime

() <

timeBound

){

herItem

=

slot.get

(

stampHolder

);

if (

stampHolder[0] == BUSY) { slot.set(null, EMPTY); return herItem; }}

if (slot.CAS(myItem

,

null, WAITING, EMPTY)){ throw new TimeoutException(); } else { herItem = slot.get(stampHolder

); slot.set(null, EMPTY); return herItem; }} break;

Exchanger State EMPTYOtherwise we ran out of time, try to reset status to EMPTY and time out

Slide190

Art of Multiprocessor Programming

190

Art of Multiprocessor Programming© Herlihy-

Shavit 2007

190

case EMPTY: // slot is free

if (

slot.compareAndSet

(

herItem

,

myItem

, WAITING, BUSY)) {

while (

System.nanoTime

() <

timeBound

){

herItem

= slot.get(stampHolder); if (stampHolder

[0] == BUSY) {

slot.set(null, EMPTY);

return

herItem; }} if (slot.compareAndSet(myItem, null, WAITING, EMPTY)){throw new TimeoutException(); } else {

herItem = slot.get(stampHolder); slot.set(null, EMPTY); return

herItem; }} break; Exchanger State EMPTYIf reset failed,someone showed up after all, so take that item

Slide191

Art of Multiprocessor Programming

191

191

case EMPTY: // slot is free

if (slot.CAS(herItem

,

myItem

, EMPTY, WAITING)) {

while (

System.nanoTime

() <

timeBound

){

herItem

=

slot.get

(

stampHolder

);

if (

stampHolder[0] == BUSY) { slot.set(null, EMPTY); return herItem;

}}

if (slot.CAS(myItem

, null, WAITING, EMPTY)){

throw new TimeoutException(); } else { herItem = slot.get(stampHolder); slot.set

(null, EMPTY); return herItem; }} break;

Exchanger State EMPTYClear slot and take that item

Slide192

Art of Multiprocessor Programming

192

192

case EMPTY: // slot is free

if (slot.CAS(herItem

,

myItem

, EMPTY, WAITING)) {

while (

System.nanoTime

() <

timeBound

){

herItem

=

slot.get

(

stampHolder

);

if (

stampHolder[0] == BUSY) { slot.set(null, EMPTY); return herItem; }}

if (slot.CAS(

myItem, null, WAITING, EMPTY)){

throw new

TimeoutException(); } else { herItem = slot.get(stampHolder); slot.set(null, EMPTY);

return herItem; }} break; Exchanger State EMPTY

If initial CAS failed,then someone else changed status from EMPTY to WAITING,so retry from start

Slide193

Art of Multiprocessor Programming

193

193

case

WAITING: // someone waiting for me

if

(

slot.CAS

(

herItem

,

myItem

, WAITING, BUSY))

return

herItem

;

break

;

case BUSY: // others in middle of exchanging break;default: // impossible break; }

}

}}

States WAITING and BUSY

Slide194

Art of Multiprocessor Programming

194

194

case WAITING: // someone waiting for me

if (slot.CAS(

herItem

,

myItem

, WAITING, BUSY))

return

herItem

;

break;

case BUSY: // others in middle of exchanging

break;

default: // impossible

break;

}

} }}States WAITING and BUSY

someone is waiting to exchange,

so try to CAS my item in

and change state to

BUSY

Slide195

Art of Multiprocessor Programming

195

195

case WAITING: // someone waiting for me

if (slot.CAS

(

herItem

,

myItem

, WAITING, BUSY))

return

herItem

;

break;

case BUSY: // others in middle of exchanging

break;

default: // impossible

break;

} } }}States WAITING and BUSY

If successful, return other’s item,

otherwise someone else took it,

so try again from start

Slide196

Art of Multiprocessor Programming

196

196

case WAITING: // someone waiting for me

if (slot.CAS

(

herItem

,

myItem

, WAITING, BUSY))

return

herItem

;

break;

case

BUSY:

// others in middle of exchanging

break

;

default: // impossible

break; } } }}States WAITING and BUSY

If

BUSY

,

other threads exchanging, so start again

Slide197

Art of Multiprocessor Programming

197

197

The Exchanger Slot Exchanger is lock-freeBecause the only way an exchange can fail is if others repeatedly succeeded or no-one showed upThe slot we need does not require symmetric exchange

Slide198

Art of Multiprocessor Programming

198

198

public class

EliminationArray {

public

T visit(T value,

int

range)

throws

TimeoutException

{

int

slot =

random.nextInt

(range);

int nanodur = convertToNanos(duration, timeUnit)); return (exchanger[slot].exchange(value, nanodur) }}

Back to the Stack: the Elimination Array

Slide199

Art of Multiprocessor Programming

199

199

public class

EliminationArray {

public

T visit(T value,

int

range)

throws

TimeoutException

{

int

slot =

random.nextInt

(range);

int nanodur = convertToNanos(duration, timeUnit)); return (exchanger[slot].exchange(value, nanodur

)

}}

Elimination Array

visit the elimination arraywith fixed value and range

Slide200

Art of Multiprocessor Programming

200

200

public class

EliminationArray {

public T visit(T value,

int

range)

throws

TimeoutException

{

int

slot =

random.nextInt

(range);

int

nanodur = convertToNanos(duration, timeUnit)); return (exchanger[slot].exchange(value, nanodur)

}}

Elimination Array

Pick a random array entry

Slide201

Art of Multiprocessor Programming

201

201

public class

EliminationArray {

public T visit(T value,

int

range)

throws

TimeoutException

{

int

slot =

random.nextInt

(range);

int

nanodur

= convertToNanos(duration, timeUnit)); return (exchanger[slot].exchange(value,

nanodur

) }}

Elimination Array

Exchange value or time out

Slide202

Art of Multiprocessor Programming

202

202

public

void push(T value) {

...

while

(

true

) {

if

(

tryPush

(node)) {

return

;

}

else

try { T otherValue = eliminationArray.visit(value,policy.range); if (otherValue

==

null) {

return

; }} Elimination Stack Push

Slide203

Art of Multiprocessor Programming

203

203

public void push(T value) {

... while (true) {

if

(

tryPush

(node)) {

return

;

} else try {

T

otherValue

=

eliminationArray.visit

(

value,policy.range

); if (otherValue == null) { return; }} Elimination Stack Push

First, try to push

Slide204

Art of Multiprocessor Programming

204

204

public void push(T value) {

...

while (true) {

if (

tryPush

(node)) {

return;

}

else try

{

T

otherValue

=

eliminationArray.visit

(

value,policy.range

);

if (otherValue == null) { return; }} Elimination Stack Push

If I failed,

backoff

& try to eliminate

Slide205

Art of Multiprocessor Programming

205

205

public void push(T value) {

... while (true) {

if (

tryPush

(node)) {

return;

} else try {

T

otherValue

=

eliminationArray.visit

(

value,policy.range

);

if (otherValue == null) { return; }} Elimination Stack Push

Value pushed and range to try

Slide206

Art of Multiprocessor Programming

206

206

public void push(T value) {

... while (true) {

if (

tryPush

(node)) {

return;

} else try {

T

otherValue

=

eliminationArray.visit

(

value,policy.range

);

if (otherValue == null) { return; }}

Elimination Stack Push

Only

pop()

leaves null,so elimination was successful

Slide207

Art of Multiprocessor Programming

207

207

public void push(T value) {

... while (true) {

if (

tryPush

(node)) {

return;

} else try {

T

otherValue

=

eliminationArray.visit

(

value,policy.range

);

if (otherValue == null) { return; }} Elimination Stack Push

Otherwise, retry

push()

on lock-free stack

Slide208

Art of Multiprocessor Programming

208

208

public

T pop() { ...

while

(

true

) {

if

(

tryPop

()) {

return

returnNode.value

;

}

else

try { T otherValue = eliminationArray.visit(null,policy.range; if

(

otherValue != null

) {

return otherValue; } }}} Elimination Stack Pop

Slide209

Art of Multiprocessor Programming

209

209

public T pop() {

... while (true) {

if (

tryPop

()) {

return

returnNode.value

;

} else

try {

T

otherValue

=

eliminationArray.visit

(

null,policy.range

;

if ( otherValue != null) { return

otherValue

; }

}

}} Elimination Stack PopIf value not null, other thread is a push(),so elimination succeeded

Slide210

Art of Multiprocessor Programming

210

210

SummaryWe saw both

lock-based and lock-free implementations of queues and stacks

Don’t be quick to declare a data structure

inherently sequential

Linearizable

stack is not inherently sequential (though it is

in the

worst case)

ABA is a real problem, pay attention

Slide211

Art of Multiprocessor Programming

211

211

 

        

This work is licensed under a

Creative Commons Attribution-

ShareAlike

2.5 License

.

You are free

:

to Share

— to copy, distribute and transmit the work

to Remix

— to adapt the work

Under the following conditions

:

Attribution

. You must attribute the work to “The Art of Multiprocessor Programming” (but not in any way that suggests that the authors endorse you or your use of the work).

Share Alike

. If you alter, transform, or build upon this work, you may distribute the resulting work only under the same, similar or a compatible license.

For any reuse or distribution, you must make clear to others the license terms of this work. The best way to do this is with a link to

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.