Herlihy Ch 9. Linked Lists: The Role of Locking Non-Blocking - - PowerPoint PPT Presentation

herlihy ch 9 linked lists the role of locking non
SMART_READER_LITE
LIVE PREVIEW

Herlihy Ch 9. Linked Lists: The Role of Locking Non-Blocking - - PowerPoint PPT Presentation

Herlihy Ch 9. Linked Lists: The Role of Locking Non-Blocking Synchronization BJRN A. JOHNSSON bjorn_a.johnsson@cs.lth.se bjorn_a.johnsson@cs.lth.se Overview? So far: Coarse- and fine-grained synchronization Optimistic


slide-1
SLIDE 1

bjorn_a.johnsson@cs.lth.se bjorn_a.johnsson@cs.lth.se

Herlihy Ch 9. Linked Lists: The Role of Locking

Non-Blocking Synchronization

BJÖRN A. JOHNSSON

slide-2
SLIDE 2

bjorn_a.johnsson@cs.lth.se bjorn_a.johnsson@cs.lth.se

Overview?

  • So far:

– Coarse- and fine-grained synchronization – Optimistic synchronization – Lazy synchronization

  • Now: Non-blocking synchronization
slide-3
SLIDE 3

bjorn_a.johnsson@cs.lth.se bjorn_a.johnsson@cs.lth.se

Naïve: just compareAndSet()

X Y X Y

slide-4
SLIDE 4

bjorn_a.johnsson@cs.lth.se bjorn_a.johnsson@cs.lth.se

AtomicMarkableReference<T>

Pragma 9.8.1. An AtomicMarkableReference<T> is an object from the java.util.concurrent.atomic package that encapsulates both a reference to an

  • bject of type T and a Boolean mark. These fields can be updated atomically, either together
  • r individually. For example, the compareAndSet() method tests the expected reference

and mark values, and if both tests succeed, replaces them with updated reference and mark

  • values. As shorthand, the attemptMark() method tests an expected reference value and if

the test succeeds, replaces it with a new mark value. The get() method has an unusual interface: it returns the object’s reference value and stores the mark value in a Boolean array argument. 1 public boolean compareAndSet(T expectedReference,
 2 T newReference,
 3 boolean expectedMark,
 4 boolean newMark);
 5 public boolean attemptMark(T expectedReference,
 6 boolean newMark);
 7 public T get(boolean[] marked);

slide-5
SLIDE 5

bjorn_a.johnsson@cs.lth.se bjorn_a.johnsson@cs.lth.se

Revisions…

  • Node’s next field now

AtomicMarkableReference<Node>

  • Thread A logically removes currA by ”marking” it’s next
  • Physical removal by other traversing threads

– add() & remove() – traverse + physically remove marked nodes on the path to their target node1

  • contains() same as in LazyList – performs no

modifications to list

1 1 Why? Exercise, that’s why!

slide-6
SLIDE 6

bjorn_a.johnsson@cs.lth.se bjorn_a.johnsson@cs.lth.se

Code 1(3)

public public Window find(Node head, Window find(Node head, int int key) { key) { Node Node pred pred = = null null, , curr curr = = null null, , succ succ = = null null; boolean boolean[] marked = { [] marked = {false false}; }; boolean boolean snip; snip; // physical remove OK? // physical remove OK? retry: retry: while while ( (true true) { ) { pred pred = head; = head; curr curr = = pred.next.getReference pred.next.getReference(); (); while while ( (true true) { ) { succ succ = = curr.next.get curr.next.get(marked); (marked); while while (marked[0]) { (marked[0]) { // physically remove! snip = snip = pred.next.compareAndSet pred.next.compareAndSet( curr curr, , succ succ, , false false, , false false); ); if if (!snip) (!snip) continue continue retry; retry; curr curr = = succ succ; succ succ = = curr.next.get curr.next.get(marked); (marked); } } if if ( (curr.key curr.key >= key) >= key) return return new new Window( Window(pred pred, , curr curr); ); pred pred = = curr curr; curr curr = = succ succ; } } } } } class class Window { Window { public public Node Node pred pred, , curr curr; Window(Node Window(Node myPred myPred, Node , Node myCurr myCurr) { ) { pred pred = = myPred myPred; ; curr curr = = myCurr myCurr; } } }

!

slide-7
SLIDE 7

bjorn_a.johnsson@cs.lth.se bjorn_a.johnsson@cs.lth.se

Code 2(3)

public public boolean boolean add(T item) { add(T item) { int int key = key = item.hashCode item.hashCode(); (); while while ( (true true) { ) { Window window = find(head, key); Window window = find(head, key); Node Node pred pred = = window. window.pred pred, , curr curr = = window. window.curr curr; if if ( (curr.key curr.key == key) { == key) { return return false false; } } else else { { Node node = Node node = new new Node(item); Node(item); node.next node.next = = new new AtomicMarkableReference AtomicMarkableReference(curr curr, , false false); ); if if ( (pred.next.compareAndSet pred.next.compareAndSet(curr curr, node, , node, false false, , false false)) )) return return true true; } } } } } public public boolean boolean remove remove(T item) { (T item) { int int key key = = item.hashCode item.hashCode(); (); boolean boolean snip; snip; // // logical logical remove remove OK? OK? while while ( (true true) { ) { Window Window window window = find(head, = find(head, key key); ); Node Node pred pred = = window. window.pred pred, , curr curr = = window. window.curr curr; if if ( (curr.key curr.key != key) { != key) { return return false false; } } else else { { Node Node succ succ = = curr.next.getReference curr.next.getReference(); (); snip = snip = curr.next.compareAndSet curr.next.compareAndSet ( (succ succ, , succ succ, , false false, , true true); ); if if (!snip) (!snip) continue continue; pred.next.compareAndSet pred.next.compareAndSet(curr curr, , succ succ, , false false, , false false); ); return return true true; } } } } }

! ! !

slide-8
SLIDE 8

bjorn_a.johnsson@cs.lth.se bjorn_a.johnsson@cs.lth.se

Code 2(3)

public public boolean boolean contains(T item) { contains(T item) { boolean boolean[] marked = [] marked = false false; int int key = key = item.hashCode item.hashCode(); (); Node curr = head; while while ( (curr.key curr.key < key) { < key) { curr = curr.next.getReference(); Node succ = curr.next.get(marked); } return return ( (curr.key curr.key == key && !marked[0]) == key && !marked[0]) }

slide-9
SLIDE 9

bjorn_a.johnsson@cs.lth.se bjorn_a.johnsson@cs.lth.se

Discussion

  • Granularity/lock-frequency gradually reduced

⇒ Fully nonblocking list!

  • LockFreeList guarantees progress in the face of arbitrary
  • delays. Price for strong progress guarantees:

– The need to support atomic modification of next has an added performance cost – Concurrent cleanup when traversing can cause contention; may force ”unnecessary” traversal restart

  • LazyList – no progress guarantees (blocks), but:

– None of LockFreeList’s weaknesses

  • Decision of approach depends on application
slide-10
SLIDE 10

bjorn_a.johnsson@cs.lth.se bjorn_a.johnsson@cs.lth.se

slide-11
SLIDE 11

bjorn_a.johnsson@cs.lth.se bjorn_a.johnsson@cs.lth.se

Exercise!

In the LockFreeList algorithm, why must threads that add/remove nodes never traverse marked nodes, but instead physically remove them? Illustrate your answer with a figure(s) similar to those in the chapter. Clarify your illustration(s) with a short explanation.