lecture 7 concurrent queues and stacks › wies › teaching › ppc-14 › material ›...

166
Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks Based on companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit Modified by Thomas Wies New York University

Upload: others

Post on 23-Jun-2020

5 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

Based on companion slides for The Art of Multiprocessor Programming

by Maurice Herlihy & Nir Shavit

Modified by Thomas Wies

New York University

TexPoint fonts used in EMF. Read the TexPoint manual before you delete this box.: AAAA

Page 2: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

2 2

The Five-Fold Path

• Coarse-grained locking

• Fine-grained locking

• Optimistic synchronization

• Lazy synchronization

• Lock-free synchronization

Page 3: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

3 3

Another Fundamental Problem

• I told you about

– Sets implemented by linked lists

• Next: queues

• Next: stacks

Page 4: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

4 4

Queues & Stacks

• pool of items

Page 5: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

5 5

Queues

deq()/ enq( )

Total order

First in

First out

Page 6: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

6 6

Stacks

pop()/

push( )

Total order

Last in

First out

Page 7: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

7 7

Bounded

• Fixed capacity

• Good when resources an issue

Page 8: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

8 8

Unbounded

• Unlimited capacity

• Often more convenient

Page 9: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

9

Blocking

zzz …

Block on attempt to remove from empty stack or queue

Page 10: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

10

Blocking

zzz …

Block on attempt to add to full bounded stack or queue

Page 11: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

11

Non-Blocking

Ouch!

Throw exception on attempt to remove from empty stack or queue

Page 12: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

12 12

This Lecture

• Queue

– Bounded, blocking, lock-based

– Unbounded, non-blocking, lock-free

• Stack

– Unbounded, non-blocking lock-free

– Elimination-backoff algorithm

Page 13: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

13 13

Queue: Concurrency

enq(x) y=deq()

enq() and deq()

work at different

ends of the object

tail head

Page 14: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

14 14

Concurrency

enq(x)

Challenge: what if

the queue is empty

or full?

y=deq()

Page 15: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

15 15

Bounded Queue

Sentinel

head

tail

Page 16: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

16 16

Bounded Queue

head

tail

First actual item

Page 17: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

17 17

Bounded Queue

head

tail

Lock out other

deq() calls

deqLock

Page 18: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

18 18

Bounded Queue

head

tail

Lock out other

enq() calls

deqLock

enqLock

Page 19: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

19 19

Not Done Yet

Need to tell whether

queue is full or

empty

head

tail

deqLock

enqLock

Page 20: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

20 20

Not Done Yet

head

tail

deqLock

enqLock

Max size is 8 items

size

1

Page 21: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

21 21

Not Done Yet

head

tail

deqLock

enqLock

Incremented by enq()

Decremented by deq()

size

1

Page 22: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

22 22

Enqueuer

head

tail

deqLock

enqLock

size

1

Lock enqLock

Page 23: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

23 23

Enqueuer

head

tail

deqLock

enqLock

size

1

Read size

OK

Page 24: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

24 24

Enqueuer

head

tail

deqLock

enqLock

size

1

No need to

lock tail

Page 25: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

25 25

Enqueuer

head

tail

deqLock

enqLock

size

1

Enqueue Node

Page 26: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

26 26

Enqueuer

head

tail

deqLock

enqLock

size

1 2

getAndincrement()

Page 27: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

27 27

Enqueuer

head

tail

deqLock

enqLock

size

8 Release lock

2

Page 28: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

28 28

Enqueuer

head

tail

deqLock

enqLock

size

2

If queue was empty,

notify waiting dequeuers

Page 29: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

29 29

Unsuccesful Enqueuer

head

tail

deqLock

enqLock

size

8

Uh-oh

Read size

Page 30: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

30 30

Dequeuer

head

tail

deqLock

enqLock

size

2

Lock deqLock

Page 31: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

31 31

Dequeuer

head

tail

deqLock

enqLock

size

2

Read sentinel’s

next field

OK

Page 32: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

32 32

Dequeuer

head

tail

deqLock

enqLock

size

2

Read value

Page 33: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

33 33

Dequeuer

head

tail

deqLock

enqLock

size

2

Make first Node

new sentinel

Page 34: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

34 34

Dequeuer

head

tail

deqLock

enqLock

size

1

Decrement

size

Page 35: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

35 35

Dequeuer

head

tail

deqLock

enqLock

size

1 Release

deqLock

Page 36: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

36 36

Unsuccesful Dequeuer

head

tail

deqLock

enqLock

size

0

Read sentinel’s

next field

uh-oh

Page 37: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

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

}

Page 38: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

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

Page 39: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

39 39

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

Page 40: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

40 40

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

Page 41: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

41 41

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

Page 42: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

42 42

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

}

}

Page 43: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

43 43

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 One

Lock and unlock

enq lock

Page 44: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

44 44

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 One

Wait while queue is full …

Page 45: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

45 45

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 One

when await() returns, you

might still fail the test !

Page 46: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

46 46

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 Afraid

After the loop: how do we know the

queue won’t become full again?

Page 47: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

47 47

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 One

Add new node

Page 48: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

48 48

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 One

If queue was empty, wake

frustrated dequeuers

Page 49: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

49 49

Beware Lost Wake-Ups

Cri

tical S

ecti

on

waiting room

lock()

Queue empty

so signal ()

enq( )

unlock()

Yawn!

Page 50: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

50 50

Lost Wake-Up

Cri

tical S

ecti

on

waiting room

lock()

enq( )

unlock()

Yawn!

Queue not

empty so no

need to signal

Page 51: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

51 51

Lost Wake-Up

Cri

tical S

ecti

on

waiting room

Yawn!

Page 52: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

52 52

Lost Wake-Up

Cri

tical S

ecti

on

waiting room

Found it

Page 53: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

53 53

What’s Wrong Here?

Cri

tical S

ecti

on

waiting room

Still waiting ….!

Page 54: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

54 54

Enq Method Part Deux

public void enq(T x) {

if (mustWakeDequeuers) {

deqLock.lock();

try {

notEmptyCondition.signalAll();

} finally {

deqLock.unlock();

}

}

}

Page 55: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

55 55

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?

Page 56: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

56 56

public void enq(T x) {

if (mustWakeDequeuers) {

deqLock.lock();

try {

notEmptyCondition.signalAll();

} finally {

deqLock.unlock();

}

}

}

Enq Method Part Deux

Lock and

unlock deq lock

Page 57: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

57 57

public void enq(T x) {

if (mustWakeDequeuers) {

deqLock.lock();

try {

notEmptyCondition.signalAll();

} finally {

deqLock.unlock();

}

}

}

Enq Method Part Deux

Signal dequeuers that

queue is no longer empty

Page 58: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

58 58

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?

Page 59: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

59 59

Split the Counter

• The enq() method

– Increments only

– Cares only if value is capacity

• The deq() method

– Decrements only

– Cares only if value is zero

Page 60: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

60 60

Split Counter

• Enqueuer increments enqSize

• Dequeuer decrements deqSize

• When enqueuer runs out

– Locks deqLock

– computes size = enqSize - DeqSize

• Intermittent synchronization

– Not with each method call

– Need both locks! (careful …)

Page 61: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

61 61

A Lock-Free Queue

Sentinel

head

tail

Page 62: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

62 62

Compare and Set

CAS

Page 63: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

63 63

Enqueue

head

tail

enq( )

Page 64: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

64 64

Enqueue

head

tail

Page 65: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

65 65

Logical Enqueue

head

tail

CAS

Page 66: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

66 66

Physical Enqueue

head

tail CAS

Page 67: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

67 67

Enqueue

• These two steps are not atomic

• The tail field refers to either

– Actual last Node (good)

– Penultimate Node (not so good)

• Be prepared!

Page 68: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

68 68

Enqueue

• What do you do if you find

– A trailing tail?

• Stop and help fix it

– If tail node has non-null next field

– CAS the queue’s tail field to tail.next

Page 69: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

69 69

When CASs Fail

• During logical enqueue

– Abandon hope, restart

– Still lock-free (why?)

• During physical enqueue

– Ignore it (why?)

Page 70: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

70 70

Dequeuer

head

tail

Read value

Page 71: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

71 71

Dequeuer

head

tail

Make first Node

new sentinel

CAS

Page 72: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

72 72

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?

Page 73: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

73 73

Dequeuer

head

tail

CAS

Can recycle

Page 74: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

74 74

Simple Solution

• Each thread has a free list of unused

queue nodes

• Allocate node: pop from list

• Free node: push onto list

• Deal with underflow somehow …

Page 75: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

75 75

Why Recycling is Hard

Free pool

head tail

Want to

redirect

head from

gray to red

zzz…

Page 76: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

76 76

Both Nodes Reclaimed

Free pool

zzz

head tail

Page 77: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

77 77

One Node Recycled

Free pool

Yawn!

head tail

Page 78: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

78 78

Why Recycling is Hard

Free pool

CAS

head tail

OK, here

I go!

Page 79: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

79 79

Recycle FAIL

Free pool

OMG what went wrong?

head tail

Page 80: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

80 80

The Dreaded ABA Problem head tail

Head reference has value A

Thread reads value A

Page 81: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

81 81

Dreaded ABA continued

zzz

head tail

Head reference has value B

Node A freed

Page 82: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

82 82

Dreaded ABA continued

Yawn!

head tail

Head reference has value A again

Node A recycled and reinitialized

Page 83: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

83 83

Dreaded ABA continued

CAS

head tail

CAS succeeds because references match,

even though reference’s meaning has changed

Page 84: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

84 84

The Dreaded ABA FAIL

• Is a result of CAS() semantics

– blame Sun, Intel, AMD, …

• Not with Load-Locked/Store-Conditional

– Good for IBM, ARM?

Page 85: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

85 85

Dreaded ABA – A Solution

• Tag each pointer with a counter

• Unique over lifetime of node

• Pointer size vs word size issues

• Overflow?

– Don’t worry be happy?

– Bounded tags?

• AtomicStampedReference class

Page 86: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

86 86

Atomic Stamped Reference

• AtomicStampedReference class

– Java.util.concurrent.atomic package

address S

Stamp

Reference

Can get reference & stamp atomically

Page 87: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

87 87

Concurrent Stack

• Methods

– push(x)

– pop()

• Last-in, First-out (LIFO) order

• Lock-Free!

Page 88: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

88 88

Empty Stack

Top

Page 89: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

89 89

Push

Top

Page 90: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

90 90

Push

Top CAS

Page 91: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

91 91

Push

Top

Page 92: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

92 92

Push

Top

Page 93: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

93 93

Push

Top

Page 94: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

94 94

Push

Top CAS

Page 95: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

95 95

Push

Top

Page 96: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

96 96

Pop

Top

Page 97: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

97 97

Pop

Top CAS

Page 98: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

98 98

Pop

Top CAS

mine!

Page 99: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

99 99

Pop

Top CAS

Page 100: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

100 100

Pop

Top

Page 101: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

101 101

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

Page 102: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

102 102

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

tryPush attempts to push a node

Page 103: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

103 103

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

Read top value

Page 104: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

104 104

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

Page 105: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

105 105

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

Try to swing top, return success or failure

Page 106: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

106 106

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

Push calls tryPush

Page 107: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

107 107

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

Create new node

Page 108: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

108 108

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

Page 109: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

109 109

Lock-free Stack

• Good

– No locking

• Bad

– Without GC, fear ABA

– Without backoff, huge contention at top

– In any case, no parallelism

Page 110: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

110 110

Big Question

• Are stacks inherently sequential?

• Reasons why

– Every pop() call fights for top item

• Reasons why not

– Stay tuned …

Page 111: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

111 111

Elimination-Backoff Stack

• How to

– “turn contention into parallelism”

• Replace familiar

– exponential backoff

• With alternative

– elimination-backoff

Page 112: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

112 112

Observation

Push( )

Pop()

linearizable stack

After an equal number

of pushes and pops,

stack stays the same Yes!

Page 113: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

113 113

Idea: Elimination Array

Push( )

Pop()

stack

Pick at

random

Pick at

random Elimination

Array

Page 114: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

114 114

Push Collides With Pop

Push( )

Pop()

stack

continue

continue

No need to

access stack Yes!

Page 115: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

115 115

No Collision

Push( )

Pop()

stack

If no collision,

access stack

If pushes collide or

pops collide

access stack

Page 116: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

116 116

Elimination-Backoff Stack

• Lock-free stack + elimination array

• Access Lock-free stack,

– If uncontended, apply operation

– if contended, back off to elimination array

and attempt elimination

Page 117: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

117 117

Elimination-Backoff Stack

Push( )

Pop() Top CAS

If CAS fails, back off

Page 118: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

118 118

Dynamic Range and Delay

Push( )

Pick random range and

max waiting time based

on level of contention

encountered

Page 119: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

119 119

Linearizability

• Un-eliminated calls

– linearized as before

• Eliminated calls:

– linearize pop() immediately after matching

push()

• Combination is a linearizable stack

Page 120: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

120 120

Un-Eliminated Linearizability

push(v1)

time time

push(v1)

pop(v1) pop(v1)

Page 121: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

121 121

Eliminated Linearizability

pop(v2) push(v1)

push(v2)

time time

push(v2)

pop(v2) push(v1)

pop(v1)

Collision

Point

Red calls are

eliminated

pop(v1)

Page 122: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

122 122

Backoff Has Dual Effect

• Elimination introduces parallelism

• Backoff to array cuts contention on lock-

free stack

• Elimination in array cuts down number

of threads accessing lock-free stack

Page 123: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

123 123

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

Page 124: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

124 124

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

An array of Exchangers

Page 125: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

125 125

public class Exchanger<T> {

AtomicStampedReference<T> slot

= new AtomicStampedReference<T>(null, 0);

Digression: A Lock-Free

Exchanger

Page 126: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

126 126

public class Exchanger<T> {

AtomicStampedReference<T> slot

= new AtomicStampedReference<T>(null, 0);

A Lock-Free Exchanger

Atomically modifiable

reference + status

Page 127: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

127 127

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

Page 128: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

Art of Multiprocessor Programming 128 128

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

Page 129: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

Art of Multiprocessor Programming 129 129

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

Page 130: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

130 130

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

Loop until timeout

Page 131: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

131 131

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

Get other’s item and status

Page 132: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

132 132

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

An Exchanger has three possible states

Page 133: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

133 133

Lock-free Exchanger

EMPTY

Page 134: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

134 134

EMPTY

Lock-free Exchanger

CAS

Page 135: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

135 135

WAITING

Lock-free Exchanger

Page 136: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

136 136

Lock-free Exchanger

In search of

partner …

WAITING

Page 137: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

137 137

WAITING

Lock-free Exchanger

Slot

Still waiting …

Try to exchange

item and set

status to BUSY

CAS

Page 138: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

138 138

BUSY

Lock-free Exchanger

Slot

Partner showed

up, take item and

reset to EMPTY

item status

Page 139: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

139 139

EMPTY BUSY

Lock-free Exchanger

Slot

item status

Partner showed

up, take item and

reset to EMPTY

Page 140: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

140 140

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

Page 141: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

141 141

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

Page 142: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

142 142

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

Page 143: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

143 143

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

myItem was taken,

so return herItem

that was put in its place

Page 144: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

144 144

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

Otherwise we ran out of time,

try to reset status to EMPTY

and time out

Page 145: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

145 145

case EMPTY: // slot is free

if (slot.CAS(herItem, myItem, WAITING, BUSY)) {

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 reset failed,

someone showed up after all,

so take that item

Page 146: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

146 146

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

Clear slot and take that item

Page 147: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

147 147

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

Page 148: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

148 148

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

Page 149: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

149 149

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

Page 150: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

150 150

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

Page 151: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

151 151

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

Page 152: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

152 152

The Exchanger Slot

• Exchanger is lock-free

• Because the only way an exchange can

fail is if others repeatedly succeeded or

no-one showed up

• The slot we need does not require

symmetric exchange

Page 153: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

153 153

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

Page 154: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

154 154

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 array

with fixed value and range

Page 155: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

155 155

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

Page 156: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

156 156

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

Page 157: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

157 157

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

Page 158: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

158 158

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

Page 159: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

159 159

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

Page 160: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

160 160

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

Page 161: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

161 161

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

Page 162: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

162 162

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

Page 163: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

163 163

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

Page 164: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

164 164

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

If value not null, other thread is a push(),

so elimination succeeded

Page 165: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

165 165

Summary

• We 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 worst case)

• ABA is a real problem, pay attention

Page 166: Lecture 7 Concurrent Queues and Stacks › wies › teaching › ppc-14 › material › lecture...Programming Paradigms for Concurrency Lecture 7 – Concurrent Queues and Stacks

166 166

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.