Lamport’s Bakery Algorithm
public void lock () {
int i = ThreadID.get();
flag[i] = true;
label[i] = max(label[0], ..., label[n-1]) + 1;
while (!hasPriority(i)) {} // wait
}
public void unlock() {
flag[ThreadID.get()] = false;
}
i
writes label[i]
before j
writes label[j]
, then i
obtains lock before j
Starvation-freedom follows from 1 and 2
public void lock () {
int i = ThreadID.get();
flag[i] = true;
label[i] = max(label[0], ..., label[n-1]) + 1;
while (!hasPriority(i)) {} // wait
}
Suppose not:
Since $B$ entered CS:
Former can not happen: labels strictly increasing
Lamport’s Bakery Algorithm:
Is the bakery algorithm practical?
label
array contains $n$ indiceslabel
We cannot do better:
If $n$ threads want to achieve mutual exclusion + deadlock-freedom, must have $n$ read/write registers (variables)
lock()
requires 1,000s of readshasPriority
requires either 1,000 of reads or a more advanced data structureread
and write
AtomicBoolean
class offers, e.g.,
compareAndSet(boolean expectedValue, boolean newValue)
getAndSet(boolean newValue)
Considered mutual exclusion:
increment()
method in Counter
What about larger data structures?
Recall: a (doubly) linked list
public class MyLinkedList {
private Node head;
...
// insert a new node after nd
public void insert (Node nd, value) {
Node next = nd.getNext();
Node cur = new Node(value);
nd.next = cur;
cur.prev = nd;
cur.next = next;
if (next != null) next.prev = cur;
}
}
class Node {
public Node next;
public Node prev;
public int value;
}
What could go wrong?
public void insert (Node nd, value) {
Node next = nd.getNext();
Node cur = new Node(value);
nd.next = cur;
cur.prev = nd;
cur.next = next;
if (next != null) next.prev = cur;
}
public void insert (Node nd, value) {
Node next = nd.getNext();
Node cur = new Node(value);
nd.next = cur;
cur.prev = nd;
cur.next = next;
if (next != null) next.prev = cur;
}
public class MyLinkedList {
private Node head;
private Lock lock;
...
// insert a new node after nd
public void insert (Node nd, value) {
lock.lock();
try { // all of this is critical section
Node next = nd.getNext();
Node cur = new Node(value);
nd.next = cur;
cur.prev = nd;
cur.next = next;
if (next != null) next.prev = cur;
} finally {
lock.unlock();
}
}
}
How?
Not the whole list!
Which nodes need to be locked?
class Node {
private Lock lock;
public Node next;
public Node prev;
public int value;
public void lock() { lock.lock(); }
public void unlock() { lock.unlock(); }
}
public void insert (Node nd, value) {
Node cur = new Node(value);
nd.lock();
try {
Node next = nd.getNext();
if (next != null) next.lock();
nd.next = cur;
cur.prev = nd;
cur.next = next;
if (next != null) next.prev = cur;
} finally {
if (next != null) next.unlock();
nd.unlock();
}
}