Lecture 31: Optimistic Linked Lists
COSC 273: Parallel and Distributed Computing
Spring 2023
Annoucements
- Leaderboard submission results tomorrow
- Next leaderboard submission is Friday? Monday?
- Take-home quiz: released Wednesday (Gradescope), due Friday
Today
Concurrent Linked Lists, Three Ways:
- Coarse locking
- Fine-grained locking
- Optimistic locking
A Generic Task
Store, access, & modify collection of distinct elements:
The Set
ADT:
-
add
an element
- no effect if element already there
-
remove
an element
- check if set
contains
an element
Java SimpleSet
Interface
public interface SimpleSet<T> {
// Add an element to the SimpleSet. Returns true if the element
// was not already in the set.
boolean add(T x);
// Remove an element from the SimpleSet. Returns true if the
// element was previously in the set.
boolean remove(T x);
// Test if a given element is contained in the set.
boolean contains(T x);
}
Linked List SimpleSet
s
- Each
Node
stores:
- reference to the stored object
- reference to the next
Node
- a numerical key associated with the object
- The list stores
- reference to
head
node
- a
tail
node
-
head
and tail
have min and max key values
- nodes have strictly increasing keys
Why Keys?
Question. Why is it helpful to store keys in increasing order?
Our Goals
- Correctness, safety, liveness
- deadlock-freedom
- starvation-freedom?
- nonblocking??
- linearizability???
- Performance
Synchronization Philosophies
- Coarse-Grained (
CoarseList.java
)
- lock whole data structure for every operation
- Fine-Grained (
FineList.java
)
- only lock what is needed to avoid disaster
- Optimistic (
OptimisticList.java
)
- don’t lock anything to read, only lock to modify
- Lazy (
LazyList.java
)
- use “logical” removal, only lock occasionally
- Nonblocking (
NonblockingList.java
)
Coarse-grained Locking
One lock for whole data structure
For any operation:
- Lock entire list
- Perform operation
- Unlock list
See CoarseList.java
Coarse-grained Insertion

Step 1: Acquire Lock

Step 2: Iterate to Find Location

Step 2: Iterate to Find Location

Step 2: Iterate to Find Location

Step 3: Insert Item

Step 4: Unlock List

Coarse-grained Appraisal
Advantages:
- Easy to reason about
- Easy to implement
Disadvantages:
- No parallelism
- All operations are blocking
Fine-grained Locking
One lock per node
For any operation:
- Lock head and its next
- Hand-over-hand locking while searching
- always hold at least one lock
- Perform operation
- Release locks
See FineList.java
A Fine-grained Insertion

Step 1: Lock Initial Nodes

Step 2: Hand-over-hand Locking

Step 2: Hand-over-hand Locking

Step 2: Hand-over-hand Locking

Step 4: Unlock Nodes

An Advantage: Parallel Access

An Advantage: Parallel Access

An Advantage: Parallel Access

An Advantage: Parallel Access

An Advantage: Parallel Access

An Advantage: Parallel Access

An Advantage: Parallel Access

An Advantage: Parallel Access

An Advantage: Parallel Access

An Advantage: Parallel Access

An Advantage: Parallel Access

An Advantage: Parallel Access

Fine-grained Appraisal
Advantages:
- Parallel access
- Reasonably simple implementation
Disadvantages:
- More locking overhead
- can be much slower than coarse-grained
- All operations are blocking
Optimistic Synchronization
Fine-grained wastes resources locking
- Nodes are locked when traversed
- Locked even if not modified!
A better procedure?
- Traverse without locking
- Lock relevant nodes
- Perform operation
- Unlock nodes
A Better Way?

A Better Way?

A Better Way?

A Better Way?

A Better Way?

A Better Way?

An Issue!
Between traversing and locking
- Another thread modifies the list
- Now locked nodes aren’t the right nodes!
An Issue, Illustrated

An Issue, Illustrated

An Issue, Illustrated

An Issue, Illustrated

An Issue, Illustrated

An Issue, Illustrated

How can we Address this Issue?
Optimistic Synchronization, Validated
- Traverse without locking
- Lock relevant nodes
-
Validate list
- if validation fails, go back to Step 1
- Perform operation
- Unlock nodes
Seet OptimisticList.java
How do we Validate?
After locking, ensure that:
-
pred
is reachable from head
-
curr
is pred
’s successor
If these conditions aren’t met:
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

Implementing Validation
private 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;
}
Optimistic Appraisal
Advantages:
- Less locking than fine-grained
- More opportunities for parallelism than coarse-grained
Disadvantages:
- Validation could fail
- Not starvation-free
- even if locks are starvation-free
Time v. Threads, 8 Elements

Time v. Threads, 8,192 Elements

Coarse Time v. Threads

Fine Time v. Threads

Optimistic Time v. Threads

Next Time
Another Way: Lazy Synchronization
- don’t modify the list unless you really have to