Assumption
Peterson's Algorithm
Peterson's Algorithm 
Shared variables are created and initialized before either process starts. The
shared variables flag[0] and flag[1] are initialized to FALSE because neither
process is yet interested in the critical section. The shared variable turn is
set to either 0 or 1 randomly (or it can always be set to say 0). 
var flag: array [0..1] of
boolean; 
turn: 0..1; 
%flag[k] means that process[k] is interested in the critical section 
flag[0] := FALSE; 
flag[1] := FALSE; 
turn := random(0..1) 
After initialization, each process, which is called process i in the code (the other process is process j), runs
the following code: 
repeat 
flag[i] := TRUE; 
turn := j; 
while (flag[j] and turn=j) do no-op; 
CRITICAL SECTION 
flag[i] := FALSE; 
REMAINDER SECTION 
until FALSE; 
Information common to both processes:
turn = 0 
flag[0] = FALSE 
flag[1] = FALSE 
| EXAMPLE 1 | |
| Process 0 | Process 1 | 
| i = 0, j = 1 | i = 1, j = 0 | 
| flag[0] := TRUE turn := 1 check (flag[1] = TRUE and turn =
  1) -  
  Condition is false because flag[1] = FALSE 
  - Since condition is false, no waiting in while
  loop -  Enter the critical section - Process 0 happens to lose the processor |   | 
|   | flag[1] := TRUE turn := 0 check (flag[0] = TRUE and turn =
  0) - Since condition is true, it keeps busy waiting until it loses the processor | 
| - Process 0 resumes and continues
  until it finishes in the critical section - Leave critical section flag[0] := FALSE - Start executing the remainder
  (anything else a process does besides using the critical section) - Process 0 happens to lose the processor |   | 
|   | check (flag[0] = TRUE and turn =
  0) - This condition fails because flag[0]
  = FALSE - No more busy waiting - Enter the critical section | 
 
| EXAMPLE 2 | |
| Process 0 | Process 1 | 
| i=0, j=1 | i=1, j=0 | 
| flag[0] = TRUE turn = 1 - Lose processor here |   | 
|   | flag[1] := TRUE turn := 0 check (flag[0] = TRUE and turn =
  0) - Condition is true so Process 1 busy
  waits until it loses the processor | 
| check (flag[1] = TRUE and turn =
  1) - This condition is false because turn = 0 - No waiting in loop - Enters critical section |   | 
 
| EXAMPLE 3 | |
| Process 0 | Process 1 | 
| i=0, j=1 | i=1, j=0 | 
| flag[0] = TRUE - Lose processor here |   | 
|   | flag[1] = TRUE turn = 0 check (flag[0] = TRUE and turn =
  0) - Condition is true so, Process 1
  busy waits until it loses the processor | 
| turn := 1 check (flag[1] = TRUE and turn =
  1) - Condition is true so Process 0 busy
  waits until it loses the processor |   | 
|   | check (flag[0] = TRUE and turn =
  0) - The condition is false so, Process 1 enters the critical section | 
 
Summary of Techniques for Critical Section Problem 
Software 
Hardware
Test-and-Set
Test-and-Set Solution to the Critical Section Problem

critical section 

remainder section 
until false 
Test-and-Set(target)
result := target 
target := TRUE 
return result 
Information common to both processes:
target = FALSE 

Swap
Swap Solution to the Critical Section Problem
var = true
while (var == true) swap(lock, var);
critical section
lock = false;
remainder section
until false 
Semaphores
· operations possible on a semaphore:
o initialization
o two main operations:
o the wait and signal operations are atomic operations (e.g., the test-and-set at the top of the loop of wait is done before losing the processor)
o e.g., a resource such as a shared data structure is protected by a semaphore. You must acquire the semaphore before using the resource and release the semaphore when you are done with the shared resource.
wait(S):
	while S 
		 0 do
		0 do
		
no-op;
S.value := S.value - 1;
signal(S):  
	S := S + 1; 
	
In either case, the initial value for S:
Semaphore Solution to the Critical Selection Problem 
repeat 

critical section 

remainder section 
until false; 

	S.value := S.value - 1;
	if S.value < 0
	then begin 
	
		add this process to S.L; 
		suspend this process; 
		
end;
 actual waiting is done by the suspended process
actual waiting is done by the suspended process 
	S.value := S.value + 1; 
	if S.value 
		 0
		0 
	then begin 
	
		remove a process P from S.L; 
		wakeup(P); 
		
	end;
	

mutex: a binary semaphore used to enforce mutual exclusion (i.e., solve the critical section problem)
Implementing Semaphores 
To ensure the atomic property, the OS implementation must either:
Bounded Buffer Problem (Producer/Consumer Problem) 
 for
example, in UNIX a pipe between two processes is implemented as a 4Kb buffer
between the two processes
for
example, in UNIX a pipe between two processes is implemented as a 4Kb buffer
between the two processes 

Producer
Consumer
Information common to both processes: 
empty := n 
full := 0 
mutex := 1 
Producer Process 
repeat 
produce an item in nextp 
wait(empty); 
wait(mutex); 
add nextp to buffer 
signal(mutex); 
signal(full); 
until false;
Consumer Process 
repeat
 
 wait(full);  
 wait(mutex); 
remove an item from buffer to nextc 
signal(mutex); 
signal(empty); 
consume the item in nextc
until false;
mutex: (semaphore) initialized to 1 
empty: count of empty locations in the buffer 
 initialized
to n, the buffer size
initialized
to n, the buffer size 
full: count of full locations in the buffer 
 initialized
to 0
initialized
to 0 

The empty and full semaphores are used for process synchronization. The
mutex semaphore is used to ensure mutually exclusive access to the buffer. 
if we were to change the code in the consumer process from: 
wait(full) 
wait(mutex)
to 
wait(mutex) 
wait(full), 
then we could reach a deadlock where Process 1 is waiting for Process 2 and
Process 2 is waiting for Process 1. 

