Professional Documents
Culture Documents
Process Synchronization
N process solution
Synchronization Hardware
Semaphores
Classic Problems of
Synchronization
Monitors
Synchronization Examples
Atomic Transactions
N-Process Solution: Bakery Algorithm
“Take a number for better service...”
Before entering the CS, each Pi takes a number.
Holder of smallest number enters CS next
..but more than one process can get the same number
Shared data:
initialized to false
initialized to 0
Bakery Algorithm
Process Pi:
repeat
choosing[i]:=true;
number[i]:=max(number[0]..number[n-1])+1;
choosing[i]:=false;
for j:=0 to n-1 do {
while (choosing[j]);
while (number[j]!=0
and (number[j],j)<(number[i],i));
}
CS
number[i]:=0;
RS
forever
Bakery Algorithm: Proof
Mutual Exclusion:
If
Pi is in CS and Pk has already chosen its
number, then (number[i],i) < (number[k],k)
If they both had their numbers before the
decision, this must be true or Pi would not
have been chosen
If Pi entered its CS before Pk got its
number, Pk got a bigger number
So Pk cannot enter its CS until Pi exits.
Progress, Bounded Waiting:
Processes enter CS in FCFS order
Drawbacks of Software Solutions
Complicated to program
Busy waiting (wasted CPU cycles)
It would be more efficient to block processes
that are waiting (just as if they had requested
I/O).
This
suggests implementing the
permission/waiting function in the
Operating System
But first, let’s look at some hardware
approaches.
Hardware Solution 1: Disable Interrupts
Process Pi:
repeat
disable interrupts
critical section
enable interrupts
remainder section
forever
On a uniprocessor, mutual exclusion is preserved: while
in CS, nothing else can run
because preemption impossible
On a multiprocessor: mutual exclusion is not achieved
Interrupts are “per-CPU”
Generally not a practical solution for user programs
But could be used inside an OS
Hardware Solution 2: Special Machine
Instructions
Definition:
// remainder section
} while ( TRUE);
The Test-and-Set Instruction
An algorithm that uses testset
Test-and-Set expressed
for Mutual Exclusion:
in “C”:
Shared variable lock is
int testset(int &i) initialized to 0
{ Only the first Pi who sets lock
int rv; enters CS
rv = *i;
*i = 1;
return rv;
Process Pi:
}
repeat
Non Interruptible (atomic)! while(testset(&lock));
One instruction reads then CS
writes the same memory lock:=0;
location RS
forever
Test-and-Set Instruction
Mutual exclusion is assured: if Pi enters CS, the other Pj
are busy waiting
Satisfies progress requirement
When Pi exits CS, the selection of the next Pj to enter CS
is arbitrary: no bounded waiting (it’s a race!).
Starvation is possible.
Some processors (ex: Pentium) provide an atomic
Swap(a,b) instruction that swaps the content of a and b.
(Same drawbacks as Test-and-Set)
Swap Instruction
Definition:
} while ( TRUE);
Using Swap for Mutual Exclusion
Shared variable lock is
initialized to 0 Process Pi:
repeat
Each Pi has a local key:=1
variable key repeat
The only Pi that can swap(lock,key)
enter CS is the one until key=0;
which finds lock=0 CS
lock:=0;
This Pi excludes all other
RS
Pj by setting lock to 1
forever
(Same effect as test-
and-set)
Operating Systems or Programming
Language Support for Concurrency
Solutions based on machine instructions such as
test and set involve tricky coding.
wait(S)
sometimes called P()
– Dutch proberen: “to test”
signal(S)
sometimes called V()
– Dutch verhogen: “to increment”
Semaphore
Synchronization tool that
does not require busy wait (S) {
waiting while S <= 0 ; // no-op
Semaphore S – integer S--;
variable }
Two standard operations
modify S: wait() and signal (S) {
signal() S++;
Originally called P() }
and V()
Less complicated
Can only be accessed via
two indivisible (atomic)
operations
Semaphore as General Synchronization Tool
Counting semaphore – integer
value can range over an Semaphore S;
unrestricted domain //initialized to 1
Binary semaphore – integer wait (S);
value can range only between 0 Critical Section
and 1; can be simpler to signal (S);
implement
Also known as mutex locks
Can implement a counting
semaphore S as a binary
semaphore
Provides mutual exclusion
Semaphore Implementation
Must guarantee that no two processes can execute
wait () and signal () on the same semaphore at the
same time
Thus, implementation becomes the critical section
problem where the wait and signal code are placed
in the critical section.
Could now have busy waiting in critical section
implementation
But implementation code is short
Little busy waiting if critical section rarely occupied
Note that applications may spend lots of time in
critical sections and therefore this is not a good
solution.
Semaphore Implementation with no Busy waiting
With each semaphore there is an associated waiting
queue. Each entry in a waiting queue has two data
items:
value (of type integer)
pointer to next record in the list
Two operations:
block – place the process invoking the operation
on the appropriate waiting queue.
wakeup – remove one of processes in the waiting
queue and place it in the ready queue.
Semaphore Implementation with no Busy waiting (Cont.)
Implementation of wait:
wait (S){
value--;
if (value < 0) {
// add this process to waiting queue
block(); }
}
Implementation of signal:
Signal (S){
value++;
if (value <= 0) {
// remove a process P from the waiting queue
wakeup(P); }
}
Busy Waiting Semaphores
The simplest way to
implement
semaphores. wait(S):
while S<=0 do ;
Useful when critical S--;
sections last for a
short time, or we have
lots of CPUs.
S initialized to positive signal(S):
S++;
value (to allow
someone in at the
beginning).
Busy-Waiting Semaphores:
Observations
When S>0:
the number of processes that can execute wait(S)
without being blocked = S
When S=0: one or more processes are waiting on S
Semaphore is never negative
When S becomes >0, the first process that tests S
enters enters its CS
random selection (a race)
fails Bounded Waiting condition
Atomicity in Semaphores
The test-and-decrement
sequence in wait must be
atomic, but not the loop.
wait(S):
Signal is atomic.
No two processes can be T
allowed to execute atomic
sections simultaneously. S <= 0
Initialize mutex to 1
wait (empty);
wait (mutex);
signal (mutex);
signal (full);
} while (true);
Bounded Buffer Problem (Cont.)
The structure of the consumer process
do {
wait (full);
wait (mutex);
} while (true);