• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Advanced locking
 

Advanced locking

on

  • 472 views

 

Statistics

Views

Total Views
472
Views on SlideShare
472
Embed Views
0

Actions

Likes
0
Downloads
0
Comments
0

0 Embeds 0

No embeds

Accessibility

Upload Details

Uploaded via as Microsoft PowerPoint

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment
  • Nodes are sorted, so that it is quick to detect the absence of a node. We will assume the keys are unique. <br />
  • Use a single lock to manage all the synchronization operations. <br />
  • The problem is that there is no overlap between the locks held by the two remove() calls. <br />
  • This is because another thread could remove node b after you release pred but before you acquire curr. <br />
  • Problems with fine-grained locking: Still requires a lot of lock acquisitions and releases. Threads access disjoint items may still block each other, e.g., a thread removing the second item in the list blocks all concurrent threads searching for later nodes. <br />
  • Validation checks that pred is still reachable, and it still points to curr. <br />
  • It is possible that the trail of references leading to pred or the reference from pred to curr could have changed between when they were last read by a thread and when the thread acquires the locks (to perform the actual operation). <br /> Note that absence of interference implies that once a node has been unlinked from the list, the value of its next field does not change, so following a sequence of such links eventually leads back to the list. <br />
  • OptimisticLock works well if the cost of traversing the list twice without locking is significantly less than the cost of traversing the list once with locking. <br /> However, one drawback is that contains() are likely to be called very often, and it requires locks. <br /> Traversal does not require locking. <br /> Maintains the invariant that every unmarked node is reachable. <br /> Remove takes two steps: First, mark the target node, logically removing it, and second, redirect its predecessor’s next field, physically removing it. <br />

Advanced locking Advanced locking Presentation Transcript

  • Advanced Locking Techniques • • • • Coarse-grained Synchronization Fine-grained Synchronization Optimistic Synchronization Lazy Synchronization
  • List-based Set head pred curr tail c a b head pred a tail curr b c class node { T item; int key; Node next; }
  • Coarse-grained Synchronization • Take a sequential implementation, add a lock field, and ensure that each method call acquires and releases this lock • Simple, and works well when levels of concurrency is low • When too many threads try to access the object at the same time, the object becomes a sequential bottleneck
  • Coarse-grained Locking public class CoarseList<T> { private Node head; private Lock lock = new ReentrantLock (); public CoarseList () { head = new Node (Integer.MIN_VALUE); head.next = new Node (Integer.MAX_VALUE); } public boolean add (T item) { Node pred, curr; int key = item.hashCode (); lock.lock (); try { pred = head; curr = pred.next; while (curr.key < key) { pred = curr; curr = curr.next; } if (key == curr.key) { return false; } else { Node node = new Node (item); node.next = curr; pred.next = node; return true; } finally { lock.unlock (); } } } public boolean remove (T item) { Node pred, curr; int key = item.hashCode (); lock.lock (); try { pred = head; curr = pred.next; while (curr.key < key) { pred = curr; curr = curr.next; } } if (key = curr.key) { pred.next = curr.next; return true; } else { return false; } } finally { lock.unlock (); }
  • Fine-grained Synchronization • Improve concurrency by locking individual nodes, instead of locking the entire list • Operations interfere only when trying to access the same node at the same time • Higher concurrency, but requires a lock to be added for each node
  • Fine-grained Locking public class CoarseList<T> { private Node head; public CoarseList () { head = new Node (Integer.MIN_VALUE); head.next = new Node (Integer.MAX_VALUE); } public boolean add (T item) { int key = item.hashCode (); head.lock (); Node pred = head; try { Node curr = pred.next; curr.lock (); try { while (curr.key < key) { pred.unlock(); pred = curr; curr = curr.next; curr.lock (); } if (key == curr.key) { return false; } Node newNode = new Node (item); newNode.next = curr; pred.next = newNode; return true; } finally { curr.unlock (); } } finally { pred.unlock (); } } } public boolean remove (T item) { Node pred = null, curr = null; int key = item.hashCode (); head.lock (); try { pred = head; curr = pred.next; curr.lock(); try { while (curr.key < key) { pred.unlock (); pred = curr; curr = curr.next; curr.lock (); } if (key = curr.key) { pred.next = curr.next; return true; } return false; } finally { curr.unlock (); } } finally { pred.unlock (); } }
  • Why Two Locks? head pred a Thread A Thread B tail curr b c
  • Hand-Over-Hand Locking head pred a Thread A tail curr b c Thread B Except for the initial head node, acquire the lock for curr only while holding the lock for pred
  • Optimistic Synchronization • Search a component without acquiring any locks • When a node is found, it locks the component, and then checks whether the component has been changed • Optimistic about the possibility of conflicting
  • Optimistic Locking (1) public boolean add (T item) { int key = item.hashCode (); while (true) { Node pred = head; Node curr = pred.next; while (curr.key <= key) { pred = curr; curr = curr.next; } pred.lock(); curr.lock (); try { if (validate(pred, curr)) { if (curr.key == key) { return false; } else { Node node = new Node (item); node.next = curr; pred.next = node; return true; } } } finally { pred.unlock (); curr.unlock(); } } } public boolean remove (T item) { int key = item.hashCode (); while (true) { Node pred = head; Node curr = pred.next; while (curr.key < key) { pred = curr; curr = curr.next; } pred.lock(); curr.lock (); try { if (validate(pred, curr)) { if (curr.key == key) { pred.next = curr.next; return true; } else { return flase; } } } finally { pred.unlock (); curr.unlock(); } } }
  • Optimistic Locking (2) public boolean contains (T item) { int key = item.hashCode (); while (true) { Node pred = head; Node curr = pred.next; while (curr.key < key) { pred = curr; curr = curr.next; } try { pred.lock(); curr.lock (); if (validate(pred, curr)) { return (curr.key = key); } } finally { pred.unlock (); curr.unlock(); } } } public boolean validate ( Node pred, Node curr) { Node node = head; while (node.key <= pred.key) { if (node == pred) return pred.next = curr; node = node.next; } return false; }
  • Why validation? head pred tail curr
  • Lazy Synchronization • Postpone significant changes, e.g., physically removing a node from a linked list • Allow a list to be traversed only once without locking, and contains() is wait-free. • Require a new field marked to be added into each node
  • Lazy Locking (1) public boolean add (T item) { int key = item.hashCode (); while (true) { Node pred = head; Node curr = pred.next; while (curr.key < key) { pred = curr; curr = curr.next; } pred.lock(); try { curr.lock(); try { if (validate(pred, curr)) { if (curr.key == key) { return false; } else { Node node = new Node (item); node.next = curr; pred.next = node; return true; } } } finally { curr.unlock(); } } finally { pred.unlock (); } } } public boolean remove (T item) { int key = item.hashCode (); while (true) { Node pred = head; Node curr = pred.next; while (curr.key < key) { pred = curr; curr = curr.next; } pred.lock(); try { curr.lock (); try { if (validate(pred, curr)) { if (curr.key != key) { return false; } else { curr.marked = true; pred.next = curr.next; return flase; } } } finally { curr.unlock (); } } finally { pred.unlock (); } } }
  • Lazy Locking (2) public boolean contains (T item) { int key = item.hashCode (); Node curr = head; while (curr.key < key) { curr = curr.next; } return curr.key == key && ! curr.marked; } private boolean validate (Node pred, Node curr) { return !pred.marked && !curr.marked && pred.next = curr; }
  • Can we do better? • Non-blocking synchronization: eliminate locks entirely, relying on built-in atomic operations such as compareAndSet() for synchronization