lecture 6-2 : concurrent queues and stacks companion slides for the art of multiprocessor...

80
Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Upload: stuart-alexander

Post on 16-Dec-2015

225 views

Category:

Documents


1 download

TRANSCRIPT

Page 1: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Lecture 6-2 :Concurrent Queues and

Stacks

Companion slides forThe Art of Multiprocessor

Programmingby Maurice Herlihy & Nir Shavit

Page 2: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

pool

• Data Structure similar to Set– Does not necessarily provide contains()

method– Allows the same item to appear more than

once– get() and set()

Art of Multiprocessor Programming© Herlihy-Shavit 2007

2

public interface Pool<T> {

void put(T item);

T get();

}

Page 3: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming© Herlihy-Shavit 2007

3

Queues & Stacks

• Both: pool of items• Queue

– enq() & deq()– First-in-first-out (FIFO) order

• Stack– push() & pop()– Last-in-first-out (LIFO) order

Page 4: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming© Herlihy-Shavit 2007

4

Bounded vs Unbounded

• Bounded– Fixed capacity– Good when resources an issue

• Unbounded– Holds any number of objects

Page 5: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming© Herlihy-Shavit 2007

5

Blocking vs Non-Blocking

• Problem cases:– Removing from empty pool– Adding to full (bounded) pool

• Blocking– Caller waits until state changes

• Non-Blocking– Method throws exception

Page 6: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming© Herlihy-Shavit 2007

6

Queue: Concurrency

enq(x) y=deq()

enq() and deq() work at

different ends of the object

tail head

Page 7: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming© Herlihy-Shavit 2007

7

Concurrency

enq(x)

Challenge: what if the queue is empty or full?

y=deq()

tailhead

Page 8: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming© Herlihy-Shavit 2007

8

A Bounded Lock-Based Queue

public class BoundedQueue<T> {

ReentrantLock enqLock, deqLock;

Condition notEmptyCondition, notFullCondition;

AtomicInteger size;

Node head;

Node tail;

int capacity;

public BoundedQueue(int capacity) {

this.capacity = capacity;

this.head = new Node(null);

this.tail = head;

this.size = new AtomicInteger(0);

this.enqLock = new ReentrantLock();

this.notFullCondition = enqLock.newCondition();

this.deqLock = new ReentrantLock();

this.notEmptyCondition = deqLock.newCondition();

}

protected class Node {

public T value;

public Node next;

public Node(T x) {

value = x;

next = null;

}

}

Page 9: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

9

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 = e;

if (size.getAndIncrement() == 0) {

mustWakeDequeuers = true;

}

} finally {

enqLock.unlock();

}

if (mustWakeDequeuers) {

deqLock.lock();

try {

notEmptyCondition.signalAll();

} finally {

deqLock.unlock();

}

}

}

public T deq() {

T result;

boolean mustWakeEnqueuers = false;

deqLock.lock();

try {

while (size.get() == 0) {

notEmptyCondition.await();

result = head.next.value;

head = head.next;

if (size.getAndDecrement() == capacity) {

mustWakeEnqueuers = true;

}

} finally {

deqLock.unlock();

}

if (mustWakeEnqueuers) {

enqLock.lock();

try {

notFullCondition.signalAll();

} finally {

enqLock.unlock();

}

}

return result;

}

Page 10: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

lock

• enqLock/deqLock– At most one enqueuer/dequeuer at a time can

manipulate the queue’s fields

• Two locks– Enqueuer does not lock out dequeuer – vice versa

• Association– enqLock associated with notFullCondition– deqLock associated with notEmptyCondition

Art of Multiprocessor Programming© Herlihy-Shavit 2007

10

Page 11: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

enqueue1. Acquires enqLock2. Reads the size field3. If full, enqueuer must wait until dequeuer makes room4. enqueuer waits on notFullCondition field, releasing

enqLock temporarily, and blocking until that condition is signaled.

5. Each time the thread awakens, it checks whether there is a room, and if not, goes back to sleep

6. Insert new item into tail7. Release enqLock8. If queue was empty, notify/signal waiting dequeuers

Art of Multiprocessor Programming© Herlihy-Shavit 2007

11

Page 12: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

dequeue1. Acquires deqLock2. Reads the size field3. If empty, dequeuer must wait until item is enqueued4. dequeuer waits on notEmptyCondition field, releasing

deqLock temporarily, and blocking until that condition is signaled.

5. Each time the thread awakens, it checks whether item was enqueued, and if not, goes back to sleep

6. Assigne the value of head’s next node to “result” and reset head to head’s next node

7. Release deqLock8. If queue was full, notify/signal waiting enqueuers9. Return “result”

Art of Multiprocessor Programming© Herlihy-Shavit 2007

12

Page 13: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming 1313

Bounded Queue

Sentinel

head

tail

Page 14: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming 1414

Bounded Queue

head

tail

First actual item

Page 15: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming 1515

Bounded Queue

head

tail

Lock out other deq()

calls

deqLock

Page 16: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming 1616

Bounded Queue

head

tail

Lock out other enq()

calls

deqLock

enqLock

Page 17: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming 1717

Not Done Yet

head

tail

deqLock

enqLock

Need to tell whether queue is full or

empty

Page 18: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming 1818

Not Done Yet

head

tail

deqLock

enqLock

Max size is 8 items

size

1

Page 19: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming 1919

Not Done Yet

head

tail

deqLock

enqLock

Incremented by enq()Decremented by deq()

size

1

Page 20: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming 2020

Enqueuer

head

tail

deqLock

enqLock

size

1

Lock enqLock

Page 21: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming 2121

Enqueuer

head

tail

deqLock

enqLock

size

1

Read size

OK

Page 22: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming 2222

Enqueuer

head

tail

deqLock

enqLock

size

1

No need to lock tail

Page 23: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming 2323

Enqueuer

head

tail

deqLock

enqLock

size

1

Enqueue Node

Page 24: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming 2424

Enqueuer

head

tail

deqLock

enqLock

size

12

getAndincrement()

Page 25: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming 2525

Enqueuer

head

tail

deqLock

enqLock

size

8 Release lock2

Page 26: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming 2626

Enqueuer

head

tail

deqLock

enqLock

size

2

If queue was empty, notify

waiting dequeuers

Page 27: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming 2727

Unsuccesful Enqueuer

head

tail

deqLock

enqLock

size

8

Uh-oh

Read size

Page 28: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming 2828

Dequeuer

head

tail

deqLock

enqLock

size

2

Lock deqLock

Page 29: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming 2929

Dequeuer

head

tail

deqLock

enqLock

size

2

Read sentinel’s next field

OK

Page 30: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming 3030

Dequeuer

head

tail

deqLock

enqLock

size

2

Read value

Page 31: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming 3131

Dequeuer

head

tail

deqLock

enqLock

size

2

Make first Node new sentinel

Page 32: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming 3232

Dequeuer

head

tail

deqLock

enqLock

size

1

Decrement size

Page 33: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming 3333

Dequeuer

head

tail

deqLock

enqLock

size

1Release deqLock

Page 34: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming© Herlihy-Shavit 2007

34

Monitor Locks

• Java ReentrantLocks are monitors• Allow blocking on a condition

rather than spinning• Threads:

– acquire and release lock– wait on a condition

Page 35: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming© Herlihy-Shavit 2007

35

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

Page 36: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming© Herlihy-Shavit 2007

36

Lock Conditions

public interface Condition { void await(); boolean await(long time, TimeUnit unit); … void signal(); void signalAll(); }

Page 37: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming© Herlihy-Shavit 2007

37

public interface Condition { void await(); boolean await(long time, TimeUnit unit); … void signal(); void signalAll(); }

Lock Conditions

Release lock and wait on condition

Page 38: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming© Herlihy-Shavit 2007

38

public interface Condition { void await(); boolean await(long time, TimeUnit unit); … void signal(); void signalAll(); }

Lock Conditions

Wake up one waiting thread

Page 39: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming© Herlihy-Shavit 2007

39

public interface Condition { void await(); boolean await(long time, TimeUnit unit); … void signal(); void signalAll(); }

Lock Conditions

Wake up all waiting threads

Page 40: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming© Herlihy-Shavit 2007

40

Await

• Releases lock associated with q• Sleeps (gives up processor)• Awakens (resumes running)• Reacquires lock & returns

q.await()

Page 41: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming© Herlihy-Shavit 2007

41

Signal

• Awakens one waiting thread– Which will reacquire lock

q.signal();

Page 42: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming© Herlihy-Shavit 2007

42

Signal All

• Awakens all waiting threads– Which will each reacquire lock

q.signalAll();

Page 43: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Unbounded Lock-Free Queue (Nonblocking)

• Unbounded– No need to count the number of items

• Lock-free– Use AtomicReference<V>

• An object reference that may be updated atomically. 

– boolean compareAndSet(V expect, V update)• Atomically sets the value to the given updated value if

the current value == the expected value.

• Nonblocking– No need to provide conditions on which to wait

43

Page 44: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming 4444

A Lock-Free Queue

Sentinel

head

tail

Page 45: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming 4545

Enqueue

head

tail

Enq( )

Page 46: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming 4646

Enqueue

head

tail

Page 47: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming 4747

Logical Enqueue

head

tail

CAS

Page 48: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming 4848

Physical Enqueue

head

tailCAS

Page 49: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming 4949

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 50: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming 5050

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

• As in the universal construction

Page 51: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming 5151

When CASs Fail

• During logical enqueue– Abandon hope, restart– Still lock-free (why?)

• During physical enqueue– Ignore it (why?)

Page 52: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming 5252

Dequeuer

head

tail

Read value

Page 53: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming 5353

Dequeuer

head

tail

Make first Node new sentinel

CAS

Page 54: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming© Herlihy-Shavit 2007

54

Unbounded Lock-Free Queue(Nonblocking)

public class LockFreeQueue<T> {

private AtomicReference<Node> head;

private AtomicReference<Node> tail;

public LockFreeQueue() {

this.head = new AtomicReference<Node>(null);

this.tail = new AtomicReference<Node>(null);

}

public class Node {

public T value;

public AtomicReference<Node> next;

public Node(T value) {

this.value = value;

this.next = new AtomicReference<Node>(null);

}

}

Page 55: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

55

public void enq(T item) {

Node node = new Node(item);

while (true) {

Node last = tail.get();

Node next = last.next.get();

if (last == tail.get()) {

if (next == null) {

if (last.next.compareAndSet(next, node)) {

tail.compareAndSet(last, node);

return;

}

} else {

tail.compareAndSet(last, next);

}

}

}

}

public T deq() throws EmptyException {

while (true) {

Node first = head.get();

Node last = tail.get();

Node next = first.next.get();

if (first == head.get()) {

if (first == last) {

if (next = null) {

throw new EmptyException();

}

tail.compareAndSet(last, next);

} else {

T value = next.value;

if (head.compareAndSet(first,next))

return value;

}

}

}

}

Unbounded Lock-Free Queue(Nonblocking)

Page 56: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming 5656

Concurrent Stack

• Methods– push(x) – pop()

• Last-in, First-out (LIFO) order• Lock-Free!

Page 57: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming 5757

Empty Stack

Top

Page 58: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming 5858

Push

Top

Page 59: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming 5959

Push

TopCAS

Page 60: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming 6060

Push

Top

Page 61: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming 6161

Push

Top

Page 62: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming 6262

Push

Top

Page 63: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming 6363

Push

TopCAS

Page 64: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming 6464

Push

Top

Page 65: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming 6565

Pop

Top

Page 66: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming 6666

Pop

TopCAS

Page 67: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming 6767

Pop

TopCAS

mine!

Page 68: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming 6868

Pop

TopCAS

Page 69: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming 6969

Pop

Top

Page 70: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming 7070

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 71: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming 7171

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 72: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming 7272

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 73: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming 7373

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 74: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming 7474

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 75: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming 7575

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 76: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming 7676

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 77: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming 7777

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 78: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

78

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

}

}

protected Node tryPop( ) throws EmptyException

{

Node oldTop = top.get();

if ( oldTop == null ) {

throw new EmptyException( );

}

Node newTop = oldTop.next;

if ( top.compareAndSet( oldTop, newTop ) ) {

return oldTop;

} else { return null; }

}

public T pop() throws EmptyException {

while (true) {

Node returnNode = tryPop( );

if ( returnNode != null ) {

return returnNode.value;

} else { backoff.backoff( ); }

}

}

Unbounded Lock-Free Stack

Page 79: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming 7979

Lock-free Stack

• Good– No locking

• Bad– Without GC, fear ABA– Without backoff, huge contention at

top – In any case, no parallelism

Page 80: Lecture 6-2 : Concurrent Queues and Stacks Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit

Art of Multiprocessor Programming 8080

Question

• Are stacks inherently sequential?• Reasons why

– Every pop() call fights for top item

• Reasons why not– Think about it!