# Lecture 24: Progress and Locks

## Announcements

1. Homework 03 Draft Posted
• due Friday, April 14th
2. Short quiz on Friday, April 7th
• Given two implementations, which is faster?
• Reason about parallelism/locality of reference

## Today

1. Progress
2. Lock Implementations

## UnboundedQueue Enqueue

    public void enq (T value) {
enqLock.lock();
try {
Node nd = new Node(value);
tail.next = nd;
tail = nd;
} finally {
enqLock.unlock();
}
}


## LockFreeQueue Enqueue

    public void enq(T item) {
if (item == null) throw new NullPointerException();
Node node = new Node(item);
while (true) {
Node last = tail.get();
Node next = last.next.get();
if (last == tail.get()) {
if (next == null) {
if (last.next.compareAndSet(next, node))
tail.compareAndSet(last, node);	return;
} else {
tail.compareAndSet(last, next);}}}}


## UnboundedQueue Progress

Guarantee: Starvation Freedom (assuming lock is starvation-free)

• if all pending method calls continue to take steps, then every pending method call completes in a finite number of steps

• this is blocking progress: if even one thread stops taking steps, then all other threads can be impeded

Question. When is this “good?”

## LockFreeQueue Progress

Guarantee: Lock Freedom

• if some pending method call makes progress, then some pending method call completes in a finite number of steps

• this is nonblocking progress: if some threads stall, others are still guaranteed to make progress

## Progress, 4 Ways

Blocking Progress:

• deadlock freedom if all threads take steps, some completes in finite time
• starvation freedom if all threads take steps, all complete in finite time

Nonblocking Progress:

• lock freedom if some threads take steps, some completes in finite time
• wait freedom all threads taking steps complete in finite time

Demo: concurrent-queues.zip

## Lock Implementations

1. Peterson Lock
2. Test-and-set Lock
3. Test-and-test-and-set Lock
4. CLH Lock

## The Peterson Lock

class Peterson implements Lock {
private boolean[] flag = new boolean[2];
private int victim;
public void lock () {
int i = ThreadID.get(); int j = 1 - i;
flag[i] = true;         // set my flag
victim = i;             // set myself to be victim
while (flag[j] && victim == i) {}; }
public void unlock () { int i = ThreadID.get();
flag[i] = false; }
}


Download: peterson-lock.zip

## A Challenge

Peterson lock assumes 2 threads, with IDs 0 and 1

• How do we accomplish this?

We’ll use this thread to increment a counter

public class PetersonThread extends Thread {
private int id;
private LockedCounter ctr;
private int numIncrements;
public PetersonThread (id, ctr, numIncrements) {
super(); this.id = id; this.ctr = ctr;
this.numIncrements = numIncrements; }
public int getPetersonId() { return id; }
@Override
public void run () {
for (int i=0; i<numIncrements; ++i) { ctr.increment(); }}
}


Next week: A better way

## Making a PetersonLock

class PetersonLock {
private boolean[] flag = new boolean[2];
private int victim;
public void lock () {
.getPetersonId();
int j = 1 - i; flag[i] = true; victim = i;
while (flag[j] && victim == i) {};
}
public void unlock () {...}
}


## And Now: A Locked Counter

public class LockedCounter {
private int count = 0;
PetersonLock lock = new PetersonLock();
public void increment () {
lock.lock();
try { ++count; }
finally { lock.unlock(); }
}
return count;
}
}


What happened?

## volatile Variables

Java can make variables visible between threads:

• use volatile keyword
• individual read/write operations to volatile are atomic

Drawbacks:

• volatile variables are less efficient
• only single read/write operations are atomic
• e.g. count++ not atomic
• only primitive datatypes are visible
• if volatile SomeClass..., only the reference is treated as volatile

## What Variables Should be volatile?

• In PetersonLock?
• flag?
• victim?
• In LockedCounter?
• count?

## A Problem

Only primitive datatypes can be volatile

• volatile boolean[] flag makes the reference volatile, not the data itself

How to fix this?

## A Fix

Just make 2 boolean variables, flag0 and flag1

• Yes, I know this is ugly

## Fixing Implementation

• peteson-lock.zip

## Finally!!!

What have we done?

1. Proven correctness of a lock
• idealized model of computation
2. Implemented lock
• used Java to resemble idealized model
3. Used lock
• saw expected behavior

Theory and practice converge!

The Good:

1. It works!
2. It only uses read/write operations!

1. It only works with two threads!
2. Ugly implementation
• need a separate PetersonThread to assign IDs

Question. How could we lock more simply?

## Better Tech!

Use more advanced Atomic Objects!

Introducing the AtomicBoolean class:

• var ab = new AtomicBoolean(boolean value) make an AtomicBoolean with initial value value
• ab.get() return the current value
• ab.getAndSet(boolean newValue) atomically set the value to newValue and return the old value
• ab.compareAndSet(boolean expected, boolean new) atomically update to new if previous value was expected and return whether or not the value was updated

## A Simpler Lock?

Question. How could we use AtomicBooleans to design a simpler lock?

• no Java gymnastics to deal with thread IDs
• no complicated data structures