herlihy ch 9 linked lists the role of locking non
play

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


  1. Herlihy Ch 9. Linked Lists: The Role of Locking Non-Blocking Synchronization BJÖRN A. JOHNSSON bjorn_a.johnsson@cs.lth.se bjorn_a.johnsson@cs.lth.se

  2. Overview? • So far: – Coarse- and fine-grained synchronization – Optimistic synchronization – Lazy synchronization • Now: Non-blocking synchronization bjorn_a.johnsson@cs.lth.se bjorn_a.johnsson@cs.lth.se

  3. Naïve: just compareAndSet() � X � Y � bjorn_a.johnsson@cs.lth.se bjorn_a.johnsson@cs.lth.se X � Y �

  4. 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 object of type T and a Boolean mark. These fields can be updated atomically, either together or 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); 
 bjorn_a.johnsson@cs.lth.se bjorn_a.johnsson@cs.lth.se 5 public boolean attemptMark(T expectedReference, 
 6 boolean newMark); 
 7 public T get( boolean [] marked); �

  5. Revisions… • Node ’s next field now AtomicMarkableReference<Node> � • Thread A logically removes curr A by ”marking” it’s next � • Physical removal by other traversing threads – add() & remove() – traverse + physically remove marked nodes on the path to their target node 1 • contains() same as in LazyList – performs no modifications to list bjorn_a.johnsson@cs.lth.se bjorn_a.johnsson@cs.lth.se 1 1 Why? Exercise, that’s why!

  6. Code 1(3) public public Window find(Node head, Window find(Node head, int int key) { key) { class Window { class Window { Node Node pred pred = = null null, , curr curr = = null null, , succ succ = = null null; public public Node Node pred pred, , curr curr; boolean boolean[] marked = { [] marked = {false false}; }; Window(Node Window(Node myPred myPred, Node , Node myCurr myCurr) { ) { boolean boolean snip; snip; // physical remove OK? // physical remove OK? pred pred = = myPred myPred; ; curr curr = = myCurr myCurr; retry: while retry: 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 = pred.next.compareAndSet snip = ! � 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); bjorn_a.johnsson@cs.lth.se bjorn_a.johnsson@cs.lth.se } } 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; } } } } }

  7. Code 2(3) public public boolean boolean add(T item) { add(T item) { public boolean public boolean remove remove(T item) { (T item) { int int key = key = item.hashCode item.hashCode(); (); int int key key = = item.hashCode item.hashCode(); (); while while ( (true true) { ) { boolean boolean snip; snip; // // logical logical remove remove OK? OK? Window window = find(head, key); Window window = find(head, key); while while ( (true true) { ) { Node Node pred pred = = window. window.pred pred, , curr curr = = window. window.curr curr; Window Window window window = find(head, = find(head, key key); ); if if ( (curr.key curr.key == key) { == key) { Node pred Node pred = = window. window.pred pred, , curr curr = = window. window.curr curr; return return false false; if if ( (curr.key curr.key != key) { != key) { } } else else { { return return false false; Node node = Node node = new new Node(item); Node(item); } } else else { { node.next node.next = = new new AtomicMarkableReference AtomicMarkableReference(curr curr, , false false); ); Node Node succ succ = = curr.next.getReference curr.next.getReference(); (); ! � if if ( (pred.next.compareAndSet pred.next.compareAndSet(curr curr, node, , node, false false, , false false)) )) snip = curr.next.compareAndSet snip = curr.next.compareAndSet return return true true; ( (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; } } bjorn_a.johnsson@cs.lth.se bjorn_a.johnsson@cs.lth.se } } }

  8. 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]) } bjorn_a.johnsson@cs.lth.se bjorn_a.johnsson@cs.lth.se

  9. 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: bjorn_a.johnsson@cs.lth.se bjorn_a.johnsson@cs.lth.se – None of LockFreeList ’s weaknesses • Decision of approach depends on application

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

  11. 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 . bjorn_a.johnsson@cs.lth.se bjorn_a.johnsson@cs.lth.se

Recommend


More recommend