Introduce
e: semaphore := 1;
b[j]: semaphore := 0;
d[j]: counter := 0;
The e and the b[j] together constitute a split-binary semaphore. That is, sumOfAll b[k] + e is either a 0 or a 1.
Collect the code segments into the two groups, N[i] and A[j] and
replace them with the code shown below.
N[i] are atomic code segments with no awaits.
P(e); S[i]; PASS-BATON
A[j] are atomic code segments *with* awaits.
P(e); if not B[j] -> d[j] := d[j] + 1; V(e); P(b[j]); fi; S[j]; PASS-BATON
// Invariant I === sumOfAll b[k] == 0 ^ e=0 if . . . [] B[k] ^ d[k] > 0 -> // {I ^ B[k] ^ d[k] > 0 } d[k] := d[k] - 1; // {I ^ B[k] ^ d[k] ≥ 0 } V(b[k]) // {I ^ B[k] ^ d[k] ≥ 0 } [] . . . [] else --> V(e) fi
Initially: counter nr := 0, nw := 0, dr := 0, dw := 0 semaphore e := 1, r := 0, w := 0 Invariant: RW == ( [nr = 0] or [nw = 0] ) and nw <= 1
do true -> P(e) ; if nw = 0 -> skip [] nw > 0 -> dr++ ; V(e) ; P(r) fi nr++ ; if dr = 0 -> V(e) [] dr > 0 -> dr--; V(r) fi ...read...; P(e) ; nr-- ; if nr > 0 or dw = 0 -> V(e) [] nr = 0 and dw > 0 -> dw--; V(w) fi od
do true -> P(e) ; if nr = 0 and nw = 0 -> skip [] nr > 0 or nw > 0 -> dw++ ; V(e) ; P(w) fi ; nw++; V(e) ; ...write...; P(e) ; nw-- ; if dr = 0 and dw = 0 ->V(e) [] dw > 0 -> dw--; V(w) [] dr > 0 -> dr--; V(r) fi od
do true -> P(e); if nw = 0 -> skip [] nw > 0 or dw > 0 -> //new readers are delayed if a writer is waiting now dr++ ; V(e) ; P(r) fi ; nr++; if dr = 0 -> V(e) [] dr > 0 -> dr--; V(r) fi ...read... P(e) ; nr-- ; if nr > 0 or dw = 0 -> V(e) [] nr = 0 and dw > 0 -> dw--; V(w) fi od
do true -> P(e) ; if nr = 0 and nw = 0 -> skip [] nr > 0 or nw > 0 -> dw++ ; V(e) ; P(w) fi ; nw++; V(e) ...write...; P(e) ; nw-- ; if dr = 0 and dw = 0 -> V(e) [] dw > 0 -> dw--; V(w) [] dr > 0 and dw = 0 -> dr--; V(r) //a delayed reader is resumed only if no writer is waiting fi od