Lecture 32: Lazy Linked Lists
COSC 273: Parallel and Distributed Computing
Spring 2023
Annoucements
- Quiz on concurrent linked lists released today, due Friday
- Next leaderboard submission on Monday
- First leaderboad results soon
Last Time
Concurrent Linked Lists, Three Ways:
- Coarse locking
- lock the whole data structure for every operation
- Fine-grained locking
- lock individual nodes to avoid conflicts
- Optimistic locking
- search without locks, lock on find, then validate
Optimistic Insertion
Step 1: Traverse the List
Step 1: Traverse the List
Step 1: Traverse the List
Step 2: Acquire Locks
Step 3: Validate List - Traverse
Step 3: Validate List - pred
Reachable?
Step 3: Validate List - Is curr
next?
Step 5: Release Locks
Time v. Threads, 8 Elements
Time v. Threads, 8,192 Elements
Coarse Time v. Threads
Fine Time v. Threads
Optimistic Time v. Threads
Further Improvement?
Question. What is undesireable about optimistic locking?
Optimism and Validation
Under best circumstances:
- validation succeeds
- likely if little contention
- still traverse the list twice
Under contention:
- all operations are blocking
- contention can lead to validation failures
Observation
Operations are complicated because they consist of several steps
- hard to reason about when the operation appears to take place
- coarse/fine-grained synchronization stop other threads from seeing operations “in progress”
- optimistic synchronization may encounter “in progress” operations before locking
Overly Optimistic?
Question. What operation(s) interfere with add
/remove
and how? When do we need to validate starting at the head?
Conflicting add
Operations
Conflicting remove
Operations
Improved Validation?
Question. How could we modify remove
method to make validation more efficient?
Lazy Synchronization
A simple strategy
-
Mark a node before physical removal
- marked nodes are logically removed, still physically present
- Only marked nodes are ever removed
Validation simplified:
- Just check if nodes are marked
- No need to traverse whole list!
Lazy Operation
- Traverse without locking
- Lock relevant nodes
- Validate list
- check nodes are
- not marked
- correct relationship
- if validation fails, go back to Step 1
- Perform operation
- for removal, mark node first
- Unlock nodes
Lazy Removal Illustrated
Step 1: Traverse List
Step 1: Traverse List
Step 2: Lock Nodes
Step 3: Validate pred.next == curr
?
Step 3: Validate not marked?
Step 5: Release Locks and Done!
In Code
-
LazyList.java
in linked-lists.zip
A Node
in Code
private class Node {
T item;
int key;
Node next;
Lock lock;
volatile boolean marked;
...
}
Validation, Simplified
private boolean validate (Node pred, Node curr) {
return !pred.marked && !curr.marked && pred.next == curr;
}
Improvements?
- Limited locking as in optimistic synchronization
- Simpler validation
- faster—no second list traversal
- more likely to succeed?
- Logical removal easier to reason about
- linearization point at logical removal line
-
contains()
no longer acquires locks
- often most frequent operation
- now it is wait-free!
Time v. Threads, 8 Elements
Time v. Threads, 8,192 Elements
Further Improvements?
What could be done better?
- concurrent
add
/remove
operations can still block one another
- operations are still not starvation free
Question. Can we avoid locks entirely?