CS255
Chris Pollett
Mar 6, 2019
Input: Registers C[0] and C[1] initialized to (0,0). Output: Exactly one of the two registers has value #. 0. P[i] is initially scanning a randomly chosen register. Thereafter, it changes its current register at the end of each iteration. The local variables T[i] and B[i] are initialized to 0. 1. P[i] obtains a lock on the current register and reads (t[i],R[i]). 2. P[i] selects one of five cases: (a) case [R[i] = #]: halt; (b) case [T[i] < t[i]]: set T[i] = t[i] and B[i] = R[i] (c) case [T[i] > t[i]]: write # into the current register and halt; (d) case [T[i] = t[i], R[i] = 0, B[i] = 1]: write # into the current register and halt (e) case [otherwise]: Set T[i] = T[i] + 1 and t[i] = t[i] + 1, assign a random bit-value to B[i] , and write (t[i] , B[i]) to the current register. 3. P[i] releases the lock on its current register, moves to the other register, and returns to Step 1.
Theorem. For any `c gt 0`, Asynchronous-CPP has total cost in operations executed exceeding `c` with probability at most `2^(-Omega(c))`.
Proof. The main difference between this and the synchronous case is in Step 2 (b) and 2 (c):
To prove correctness of the protocol, we consider the two cases (2(c), 2(d)) where a processor can write a # to its current cell. At the end of an iteration, a processor's timestamp `T[i]` will equal the timestamp of the current register `t[i]`. Further # cannot be written in the first iteration by either processor. (Proof cont'd next slide).
Suppose `P[i]` has just entered case 2(c), with some timestamp `T^star[i]`, and its current cell is `C[i]` with timestamp `t^star[i] lt T[i]^star`. The only possible problem is that `P[1-i]` might write `#` into register `C[1-i]` . Suppose this error occurs, and let `t^star[1-i]` and `T^star[1-i]` be the timestamp during the iteration for the other processor.
As `P[i]` comes to `C[i]` with a timestamp of `T^star[i]` , it must have left `C[1-i]` with a timestamp before `P[1-i]` could write `#` into it. Since timestamps don't decrease `t^star[1-i] ge T^star[i]`. Further `P[1-i]` cannot have its timestamp `T^star[1-i]` exceed `t^star[i]` since it must go to `C[1-i]` from `C[i]` and the timestamp of that register never exceeds `t^star[i]`. So we have `T^star[1-i] le t^star[i] lt T^star[i] le t^star[1-i]`. This means `P[1-i]` must enter case 2(b) as `T^star[1-i] lt t^star[1-i]`. This contradicts it being able to write a #.
We can analyze the case P[i] has just entered case 2(d) in a similar way, except we would reach the conclusion that `T[1-i] le t^star[i] = T[i] le t^star[1-i]` and so it is possible that `T[1-i] = t^star[1-i]`. But if this event happens, we are in the synchronous situation so our earlier correctness argument works. Thus, we have established correctness of the algorithm.