A Tale of Two Pups

Safety Goal:
Liveness Goal:
When Finn needs to go out:
Raise flag
While Scott’s flag is raised, wait
Let Finn out
When Finn comes in, lower flag
When Ru needs to go out:
Raise flag
While Will’s flag is raised:
lower flag
wait until Will’s flag is lowered
raise flag
When Scott’s flag is up and Will’s is down, release Ru
When Ru returns, lower flag
Before letting a dog out, both Scott and Will do:
Claim. If a dog wants to go out, eventually some dog will.
Why?
Is the protocol fair?
Safety Goal:
Liveness Goals:
Two processes (threads) want to access a shared resource
Counter objectAssume:
0 and 1
ThreadID.get() returns the ID of the thread calling the methodboolean[] flag
flag[i] == true if process i wants to use resourceint victim
victim == i if process i is willing to wait (like Ru)Similar to asymmetric protocol with Finn and Ru, but can switch roles.
To obtain lock:
flag to true
victim
false, orvictim
To release lock:
flag to false
lock Pseudocode public void lock() {
int i = ThreadID.get(); // get my ID, 0 or 1
int j = 1 - i; // other thread's ID
flag[i] = true; // set my flag
victim = i; // set myself to be victim
while (flag[j] && victim == i) {
// wait
}
}
unlock Pseudocode public void unlock() {
int i = ThreadID.get();
flag[i] = false;
}
Mutual Exclusion. If both threads concurrently call lock(), then both cannot return until other calls unlock().
Starvation Freedom. If thread i calls lock() then eventually thread i returns.
Question. Why does Peterson lock achieve these properties?
Suppose not…
lock()
unlock()
In this case we say both threads enter critical section
Atomic operations:
flag[A] = true
victim = A
flag[B]
victim
flag[B] = true
victim = B
flag[A]
victim
Suppose $(B.2) \to (A.2)$:
i.e., $A $ wrote to victim last
if not, continue argument with roles of $A $ and $B $ reversed
The Peterson lock satisfies mutual exclusion!
Claim. If thread $A$ calls lock(), eventually the method will return.
public void lock() {
int i = ThreadID.get(); // get my ID, 0 or 1
int j = 1 - i; // other thread's ID
flag[i] = true; // set my flag
victim = i; // set myself to be victim
while (flag[j] && victim == i) { /*wait*/ }
}
Case 1. $A$ reads flag[B] == false or victim == B.
Claim. If thread $A$ calls lock(), eventually the method will return.
public void lock() {
int i = ThreadID.get(); // get my ID, 0 or 1
int j = 1 - i; // other thread's ID
flag[i] = true; // set my flag
victim = i; // set myself to be victim
while (flag[j] && victim == i) { /*wait*/ }
}
Case 2. $A$ reads flag[B] == true and victim == A.
Assumption. Once thread B obtains lock, eventually B calls unlock()
public void unlock() {
int i = ThreadID.get();
flag[i] = false;
}
What then happens to thread A?
The Peterson lock satisfies starvation freedom!
Locks for more threads!