EXAMPLE FILE: 2ProcessSynch

Proof of Correctness of Algorithm 3,
Chapter 6, Silberschatz & Galvin

This algorithm is due to Peterson (1981)

It solves the critical section problem for two concurrent
processes that share access to an array of two flags and a
variable called "turn".

Code for P0                                Code for P1
repeat                                     repeat
  flag[0] := true ;           1              flag[1] := true ;
  turn := 1 ;                 2              turn := 0 ;
  while (flag[1]              3              while (flag[0]
  and turn=1)                 4              and turn=0)
  do skip ;                   5              do skip ;
  .. CS(P0) ..                6              .. CS(P1) ..
  flag[0] := false ;          7              flag[1] := false ;
  .. RS(P0) ..                8              .. RS(P1) ..
until false                                until false
Mutual Exclusion Proof:
Assume that coexistence happens.  Let T0 be the instant of time that
the coexistence FIRST occurs (in the life of the two processes).
We may also assume, without loss of generality (WOLOG), that P0 arrives
in CS(P0) at time T0.  (ONE of the processes must arrive at that time,
if it is P1, then switch the names of the processes!) It follows that
P1 must either enter CS(P1) BEFORE T0, or at least at exactly time T0.
(Remember, this solution applies to a multi-PROCESSING environment, as
well as to a multi-PROGRAMMING environment, so two processes really can
do some things SIMULTANEOUSLY.)
Let T1 be the very LAST time <= to T0 that P1 enters CS(P1).  It
follows from these definitions that, P1 REMAINS in CS(P1) during the
time between T1 and T0.  (If P1 left CS(P1) after T1 and before T0,
then it would have to re-enter again no later than T0 to be there for
the "magic moment" of first coexistence.  But T1 is the LAST time <= to
T0 that P1 enters CS(P1)!)
           ^               ^        ^    ^   ^    ^
                                            T1   T0
             Fig 1.  P1 may enter CS(P1) MANY times before
                     time T0, but T1 is the LAST time no later
                     than T0 that P1 enters CS(P1).
Let T0-set be the LAST time before T0 that P0 completes the execution
of instruction 2.  Similarly, let T1-set be the LAST time before T1
that P1 completes instruction 2.  Note that between T1-set and T0, P1
REMAINS in the part of its code that is after 2 and before 7.
                               ^             ^    ^
                             T1-set          T1   T0
                            (P1 past 2)        (P1 still before 7)
                                 Fig 2.
What happens if both processes try to execute 2 at about the same time?
Our assumptions about the hardware on which the processes are running
tell us that in the event of such a "race conditon", the outcome of the
race is guaranteed to be the same as if the two instructions were
executed SEQUENTIALLY (one after the other) in some order, but not in
an order we can necessarily predict in advance.
Suppose that T1-set < T0-set (or that T1-set = T0-set and that P1 is
the "winner of the race", so that "turn" = 1 after time T0-set).  Then
T1-set <= T0-set < T0, so at time T0-set
     1.  P1 will be executing somewhere after 2 and before 7, so the
         value of flag[1] will be true, and will remain so until after
     2.  "turn" will have just been set to 1 by P0, and there will be
         no possibility of "turn" being set back to 0 until some time
         after T0.
Thus both of P0's loop conditions will remain TRUE from time T0-set,
right through to, and including, time T0: (flag[1] = true) and
(turn = 1).  But P0 enters the loop at 3 some time after T0-set, and
gets out of it no later than T0 in order to arrive in CS(P0) at time
T0.  Since P0 CAN'T get out of the loop until one of the loop
conditions becomes false, we see that we have come up against an
obvious contradiction.
So IF P0 and P1 really do come to co-exist in their CS's, it must be
that T0-set < T1-set.
           ^                   ^             ^    ^
         T0-set              T1-set          T1   T0
                            (P1 past 2)        (P1 still before 7)
                                 Fig 3.
But if THAT is true, then after T1-set but before T0, BOTH flags are
true and "turn" = 0 (it can't be 1 because P1 sets it to 0 at time
T1-set, and P0 remains in the code after 2 and before 7 all through the
time between T0-set and T0).  THAT is a contradiction, because it
implies that P1 can't get out of ITS while-loop until after T0 -- which
was defined to be a time when BOTH processes are in their CS's.
So now we have run out of possibilities.  There is no ordering of the
times T0, T1, T0-set, and T1-set that is logically consistent!  So the
assumption upon which we based our definition of these times must be
incorrect -- in short, it must be impossible for P0 and P1 to be in
their CS's concurrently.
Progress Proof:
It's quite obvious that progress is assured, so the proof is short:
If a process is executing in its remainder section, then clearly its
flag is FALSE.  Thus the other process has no difficulty getting out of
its while loop and entering the CS.  There is NO postponement of the
other process (all that has to be done is one evaluation of the loop
conditions), and the process executing in its RS has no say about
whether the other process gets in, DESPITE the fact that "turn" might
be "in its favor".
Bounded Waiting Proof:
If P0, say. has arrived in its while loop, then it can enter the CS
when flag[1] is false OR when "turn" = 0.  If P1 is executing in its
RS, its flag will be false, and P0 will enter with no wait.  If P1 is
in contention with P0 to enter its own CS, and if P1 has won the race
to set "turn", then it will enter its CS, if not P0 will enter with no
wait.  If P1 is in its CS when P0 begins its wait, or if P1 wins a race
and enters ahead of P0, it will eventually set "turn" to 0 and enter
the loop again (unless it halts! -- just kidding, in this context, it's
not "allowed" to halt).  That will assure that P0 gets in to its CS
before P1 can get in again (even if P1 is fast enough to set its flag
to false and back to true again before P0 has had time to notice).  In
any case P0 gets in after P1 gets in AT MOST ONCE.