Operating Systems
Certificate Program in Software Development
CSE-TC and CSIM, AIT
September -- November, 2003
5. Process Synchronization
(Ch. 6, S&G)
ch 7 in the 6th ed.
Objectives
– describe the synchronization problem and
some common mechanisms for solving it
OSes: 5. Synch
1
Contents
1. Motivation: Bounded Buffer
2. Critical Sections
3. Synchronization Hardware
4. Semaphores
5. Synchronization Examples
OSes: 5. Synch
continued
2
6.
Problems with Semaphores
7.
Critical Regions
8.
Monitors
9.
Synchronization in Solaris 2
10. Atomic Transactions
OSes: 5. Synch
3
1. Motivation: Bounded Buffer
bounded buffer
…..
0
producer
OSes: 5. Synch
1 2 3
write
…..
n-1
read
consumer
4
Producer Code (pseudo-Pascal)
:
repeat
. . .
/* produce an itemP */
. . .
while (counter == n) do
no-op;
buffer[in] := itemP;
in := (in+1) mod n;
counter := counter + 1;
until false;
:
OSes: 5. Synch
/* write */
5
Consumer Code
:
repeat
while (counter == 0) do
no-op;
itemC := buffer[out];
/* read */
out := (out+1) mod n;
counter := counter - 1;
. . .
/* use itemC for something */
. . .
until false;
:
OSes: 5. Synch
6
Problem
Assume counter == 5
producer run
:
counter :=
counter + 1;
:
counter
OSes: 5. Synch
consumer run
:
counter :=
counter - 1;
:
may now be 4, 5, or 6. Why?
7
Machine Language
“counter := counter + 1”
reg1 := counter
reg1 := reg1 + 1
counter := reg1
becomes:
“counter := counter - 1”
reg2 := counter
reg2 := reg2 - 1
counter := reg2
OSes: 5. Synch
becomes:
8
Execution Interleaving
The
concurrent execution of the two
processes is achieved by interleaving the
execution of each
There
are many possible interleavings,
which can lead to different values for
counter
– a different interleaving may occur each time
the processes are run
OSes: 5. Synch
9
Interleaving Example
Initially: counter == 5
Execution:
reg1 :=
reg1 :=
reg2 :=
reg2 :=
counter
counter
OSes: 5. Synch
counter
reg1 + 1
counter
reg2 - 1
:= reg1
:= reg2
//
//
//
//
//
//
reg1 ==
reg1 ==
reg2 ==
reg2 ==
counter
counter
5
6
5
4
== 6
== 4
10
Summary of Problem
Incorrect
results occur because of a race
condition over the modification of the
shared variable (counter)
The
processes must be synchronized while
they are sharing data so that the result is
predictable and correct
OSes: 5. Synch
11
2. Critical Sections
A critical
section is a segment of code
which can only be executed by one process
at a time
– all other processes are excluded
– called mutual exclusion
OSes: 5. Synch
12
Critical Section Pseudo-code
repeat
entry section
critical section
exit section
remainder section
until false;
OSes: 5. Synch
13
Implementation Features
An
implementation of the critical section
idea must have three features:
– mutual exclusion
– progress
the
next process to enter the critical region is
decided solely by looking at those waiting in their
entry sections
– bounded waiting
no
OSes: 5. Synch
process should wait forever in their entry section
14
2.1. Solutions for Two Processes
Algorithm
1 (take turns)
– shared data:
var turn: 0..1 := 0;
/* or 1 */
– Code for process i:
repeat
while (turn /== i) do no-op:
critical section;
turn := j;
progress requirement
remainder section;
not met
until false;
OSes: 5. Synch
15
Algorithm2
(who wants to enter?)
Shared data:
var flag : array [0..1] of boolean
:= {false, false};
Code for process i:
repeat
flag[i] := true;
while (flag[j]) do no-op:
critical section;
flag[i] := false;
remainder section;
progress requirement
until false;
still not met
OSes: 5. Synch
16
Algorithm 3
Combines
(Peterson, 1981)
algorithms 1 and 2
– who wants to enter?
– if both do then take turns
Shared data:
var flag : array [0..1] of boolean
:= {false, false};
var turn : 0..1 := 0;
OSes: 5. Synch
/* or 1 */
continued
17
Code for process i:
repeat
flag[i] := true;
turn := j;
while (flag[j] and turn == j) do
no-op:
critical section;
flag[i] := false;
remainder section;
until false;
OSes: 5. Synch
18
2.2. Multiple Processes
Uses
the bakery algorithm (Lamport 1974).
Each
customer (process) receives a number
on entering the store (the entry section).
The
customer with the lowest number is
served first (enters the critical region).
OSes: 5. Synch
continued
19
If
two customers have the same number,
then the one with the lowest name is served
first
– names are unique and ordered
OSes: 5. Synch
20
Pseudo-code
Shared data:
var choosing : array [0..n-1]
of boolean
:= {false .. false};
var number : array [0..n-1]
of integer
:= {0 .. 0};
OSes: 5. Synch
continued
21
Code
for process i:
repeat
choosing[i] := true;
number[i] := max(number[0], number[1],
. . ., number[n-1]) + 1;
choosing[i] := false;
for j := 0 to n-1 do
begin
while (choosing[j]) do no-op;
while ((number[j] /== 0) and
((number[j],j) < (number[i],i))) do no-op;
end;
critical section
number[i] := 0;
remainder section
until false;
OSes: 5. Synch
22
3. Synchronization Hardware
Hardware
solutions can make software
synchronization much simpler
On
a uniprocessor, the OS can disallow
interrupts while a shared variable is being
changed
– not so easy on multiprocessors
OSes: 5. Synch
continued
23
Typical
hardware support:
– atomic test-and-set of a boolean (byte)
– atomic swap of booleans (bytes)
Atomic
means an uninterruptable ‘unit’ of
work.
OSes: 5. Synch
24
3.1. Atomic Test-and-Set
function Test-and-Set(
var target : boolean) : boolean
begin
Test-and-Set := target;
target := true;
end;
OSes: 5. Synch
25
Use
lock/in lock/out result action
F
T
F
proceed
T
T
T
loop
Shared data:
var lock : boolean := false;
Process code for mutual exclusion:
repeat
while (Test-and-Set(lock) do
no-op;
critical section
lock := false;
remainder section
until false;
OSes: 5. Synch
26
3.2. Atomic Swap
procedure Swap(var a, b : boolean)
var temp : boolean;
begin
temp := a;
a := b;
b := temp;
end;
OSes: 5. Synch
27
Use
key1
in: T
key2
T
…
…
keyN lock
T
F
Shared data:
var lock : boolean := false;
Process code for m.e.:
var key : boolean:
repeat
key := true;
repeat
Swap(lock, key);
until (key == false);
critical section
lock := false;
remainder section
until false;
OSes: 5. Synch
28
3.3. Bounded Waiting
TestAndSet()
and Swap() both satisfy the
requirements of mutual exclusion and
progress
But
bounded waiting is not satisfied
We
must add an extra data structure to code
FIFO (queueing-style) behaviour
OSes: 5. Synch
29
4. Semaphores
(Dijkstra, 1965)
Semaphores
are a synchronization tool
based around two atomic operations:
OSes: 5. Synch
– wait()
sometimes called P()
– signal()
sometimes called V()
30
4.1. Definitions
same as integer
procedure wait(var S : semaphore)
begin
while (S =< 0) do
no-op;
S := S - 1;
end;
procedure signal(var S : semaphore)
begin
S := S + 1;
end;
OSes: 5. Synch
31
4.2. Mutual Exclusion with Semaphores
Shared data:
var mutex : semaphore := 1;
Process code:
repeat
wait(mutex);
critical section;
signal(mutex);
remainder section;
until false;
OSes: 5. Synch
32
4.3. Ordering Processes
Establish
a fixed order for two processes
p1 and p2 , We set semaphore Order := 0.
If
the desired order is p1 -> p2, p2 should
issue a wait(Order), and then wait until p1
issues a signal(Order).
OSes: 5. Synch
33
4.4. Counting Semaphores
Allow
N processes into a critical section,
by initialising semaphore Limit to N
– the first N processes each decrement Limit
using wait(Limit), until Limit == 0, at
which time new processes must wait
This
approach is used for controlling
access to a limited number of resources
(e.g. N resources)
OSes: 5. Synch
34
4.5. Implementations
Our wait()
implementation uses busy-waiting
– sometimes called a spinlock
An
alternative is for the process calling wait()
to block
– place itself on a wait list associated with the
semaphore
– signal() chooses a blocked process to become
ready
OSes: 5. Synch
35
New Semaphore Data Type
type semaphore =
record
value : integer;
L : list of waiting-processes;
end;
OSes: 5. Synch
36
New Operations
procedure wait(var S : semaphore)
begin
S.value := S.value - 1;
if (S.value < 0) then
begin
/* add the calling process to S.L */
. . .
block;
end;
end;
OSes: 5. Synch
continued
37
procedure signal(var S : semaphore)
begin
S.value := S.value + 1;
if (S.value =< 0) then
begin
/* remove a process P from S.L */
. . .
wakeup(P);
end;
end;
OSes: 5. Synch
38
4.6. Deadlocks & Starvation
Deadlock
occurs when every process is
waiting for a signal(S) call that can only be
carried out by one of the waiting processes.
Starvation
occurs when a waiting process
never gets selected to move into the critical
region.
OSes: 5. Synch
39
4.7. Binary Semaphores
A binary
semaphore is a specialisation of
the counting semaphore with S only having
a range of 0..1
– S starts at 0
– easy to implement
– can be used to code up counting semaphores
OSes: 5. Synch
40
5. Synchronization Examples
OSes: 5. Synch
5.1.
Bounded Buffer
5.2.
Readers and Writers
5.3.
Dining Philosophers
41
5.1. Bounded Buffer (Again)
bounded buffer
…..
0
producer
OSes: 5. Synch
1 2 3
write
…..
n-1
read
consumer
42
Implementation
Shared data:
var buffer : array[0..n-1] of Item;
var mutex : semaphore := 1;
/* for access to buffer */
var full : semaphore := 0;
/* num. of used array cells */
var empty : semaphore := n;
/* num. of empty array cells */
OSes: 5. Synch
43
Producer Code
repeat
. . .
/* produce an itemP */
. . .
wait(empty);
wait(mutex);
buffer[in] := itemP;
in := (in+1) mod n;
signal(mutex);
signal(full);
until false;
OSes: 5. Synch
44
Consumer Code
repeat
wait(full);
wait(mutex);
itemC := buffer[out];
out := (out+1) mod n;
signal(mutex);
signal(empty);
. . .
/* use itemC for something */
. . .
until false;
OSes: 5. Synch
45
5.2. Readers & Writers
Readers
make no change to the shared data
(e.g. a file)
– no synchronization problem
Writers
do change the shared data
Multiple
writers (or a writer and readers)
cause a synchronization problem.
OSes: 5. Synch
46
Many Variations
1.
Don’t keep a reader waiting unless a
writer is already using the shared data
– writers may starve
2.
Don’t keep a writer waiting
– readers may starve
OSes: 5. Synch
47
Variation 1
Shared data:
var shared-data : Item;
var readcount : integer : = 0;
/* no. of readers currently
using shared-data */
var mutex : semaphore := 1;
/* control access to readcount */
var wrt : semaphore := 1;
/* used for m.e. of writers */
OSes: 5. Synch
48
Writer’s Code
:
wait(wrt);
. . .
/* writing is performed */
. . .
signal(wrt);
:
OSes: 5. Synch
49
Reader’s Code
wait(mutex);
readcount := readcount + 1;
if (readcount == 1) then
wait(wrt);
signal(mutex);
. . .
/* reading is performed */
. . .
wait(mutex);
readcount := readcount - 1;
if (readcount == 0) then
signal(wrt);
signal(mutex);
OSes: 5. Synch
50
5.3. Dining Philosophers
Dijkstra, 1965
OSes: 5. Synch
An example of the
need to allocate several
resources (chopsticks)
among processes
(philosophers) in a
deadlock and
starvation free manner.
51
Implementation
Represent
each chopstick by a semaphore.
Shared data:
var chopstick : array[0..4]
of semaphore
:= {1,1,1,1,1};
A chopstick
is ‘picked up’ with:
wait(chopstick[pos])
and ‘set down’ with:
signal(chopstick[pos])
OSes: 5. Synch
52
Code for Philopospher i
repeat
wait( chopstick[i] );
wait( chopstick[(i+1) mod 5] );
/* . . . eat . . . */
signal( chopstick[i] );
signal( chopstick[(i+1) mod 5] );
/* . . . think . . . */
until false;
OSes: 5. Synch
53
Deadlock
This
solution avoids simultaneous use of
chopsticks (good)
But
if all the philosophers pick up their left
chopstick together, then they will deadlock
while waiting for access to their right
chopstick.
OSes: 5. Synch
54
Possible Fixes
Allow
at most 4 philosophers to be at the table
at a time.
Have
a philosopher pick up their chopsticks
only if both are available (in a critical section)
Alternate
the order that chopsticks are picked
up depending on whether the philosopher is
seated at an odd or even seat
OSes: 5. Synch
55
6. Problems with Semaphores
The
reversal of a wait() and signal() pair
will break mutual exclusion
The
omission of either a wait() or signal()
will potentially cause deadlock
These
problems are difficult to debug and
reproduce
OSes: 5. Synch
56
Higher level Synchronization
These
problems have motivated the
introduction of higher level constructs:
– critical regions
– monitors
– condition variables
These
constructs are safer, and easy to
understand
OSes: 5. Synch
57
7. Critical Regions
Shared variables are explicitly
var v : shared ItemType;
Hoare, 1972;
Brinch Hansen, 1972
declared:
A shared
variable can only be accessed within
the code part (S) of a region statement:
region v do S
– while code S is being executed, no other process
can access v
OSes: 5. Synch
58
Conditional Critical Regions
region v when B do S
– only execute S when the boolean expression B
evaluates to true, otherwise wait until B is true
– as before, while code S is being executed, no
other process can access v
OSes: 5. Synch
59
Bounded Buffer Again
Shared
data:
var buffer : shared record
pool : array[0..n-1] of Item;
count, in, out : integer;
end;
OSes: 5. Synch
60
Producer Code
region buffer when (count < n) do
begin
pool[in] := itemP;
in := (in+1) mod n;
count := count + 1;
end;
OSes: 5. Synch
61
Consumer Code
region buffer when (count > 0) do
begin
itemC := pool[out];
out := (out+1) mod n;
count := count - 1;
end;
OSes: 5. Synch
62
8. Monitors
queues associated
var
with condition
variables
Brinch Hansen, 1973
shared data
entry queue of
waiting processes
operations
Fig. 6.20, p.184
OSes: 5. Synch
initialization
code
63
Monitor Syntax
type monitor-name = monitor
variable declarations
procedure entry p1(. . .)
begin . . . end;
:
begin
initialization code
end.
OSes: 5. Synch
64
Features
When
an instance of a monitor is created, its
initialization code is executed
A procedure
can access its own variables
and those in the monitor’s variable
declarations
A monitor
only allows one process to use its
operations at a time
OSes: 5. Synch
65
An OO View of Monitors
A monitor
is similar to a class
An
instance of a monitor is similar to an
object, with all private data
Plus
synchronization: invoking any
operation (method) results in mutual
exclusion over the entire object
OSes: 5. Synch
66
8.1. Condition Variables
Notation:
var x : condition;
x.wait;
suspend
calling process
x.signal;
resumes
one of the suspended
processes waiting on x
OSes: 5. Synch
67
Condition Variables in Monitors
What
happens when signal is issued?
The
unblocked process will be placed on the
ready queue and resume from the statement
following the wait.
This
would violate mutual exclusion if both
the signaller and signalled process are
executing in the monitor at once.
OSes: 5. Synch
68
Three Possible Solutions
1.
Have the signaller leave the monitor
immediately after calling signal
2.
Have the signalled process wait until the
signaller has left the monitor
3.
Have the signaller wait until the
signalled process has left the monitor
OSes: 5. Synch
69
8.2. Dining Philosophers (Again)
Useful
data structures:
var state : array[0..4] of
(thinking, hungry, eating);
var self : array[0..4] of condition;
/* used to delay philosophers */
The
approach is to only set state[i] to
eating if its two neigbours are not eating
– i.e.
and
OSes: 5. Synch
state[(i+4) mod 5]
state[(i+1) mod 5]
=
=
eating
eating
70
Using the dining-philosophers Monitor
Shared data:
var dp : dining-philosopher;
Code
in philosopher i:
dp.pickup(i):
/* . . . eat . . . */
dp.putdown(i);
OSes: 5. Synch
71
Monitor implementation
type dining-philosophers = monitor
var state : array[0..4] of
(thinking, hungry, eating);
var self : array[0..4] of condition;
procedure entry pickup(i : 0..4)
begin
state[i] := hungry;
test(i);
if (state[i] /== eating) then
self[i].wait;
end;
OSes: 5. Synch
continued
72
procedure entry putdown(i : 0..4)
begin
state[i] := thinking;
test((i+4) mod 5);
test((i+1) mod 5);
end;
OSes: 5. Synch
continued
73
procedure test(k : 0..4)
begin
if ((state[(k+4) mod 5] /== eating)
and (state[k] == hungry)
and (state[(k+1) mod 5]
/== eating)) then
begin
state[k] := eating;
self[k].signal;
end;
end;
OSes: 5. Synch
continued
74
begin
/* initialization of monitor instance */
for i := 0 to 4 do
state[i] := thinking;
end.
OSes: 5. Synch
75
8.3. Problems with Monitors
Even
For
high level operations can be misused.
correctness, we must check:
– that all user processes always call the monitor
operations in the right order;
– that no user process bypasses the monitor and
uses a shared resource directly
– called the access-control problem
OSes: 5. Synch
76
9. Synchronization in Solaris 2
Uses
a mix of techniques:
– semaphores using spinlocks
– thread blocking
– condition variables (without monitors)
– specialised reader-writer locks on data
OSes: 5. Synch
77
10. Atomic Transactions
We
want to do all the operations of a critical
section as a single logical ‘unit’ of work
– it is either done completely or not at all
A transaction
can be viewed as a sequence
of reads and writes on shared data, ending
with a commit or abort operation
An abort
causes a partial transaction to be
rolled back
OSes: 5. Synch
78
10.1. Log-based Recovery
Atomicity
is ensured by logging transaction
operations to stable storage
– these can be replayed or used for rollback if
failure occurs
Log
details:
– transaction name, data name, old value,
new value
OSes: 5. Synch
continued
79
Write-ahead
logging:
– log a write operation before doing it
– log the transaction start and its commit
OSes: 5. Synch
80
Example
begin transaction
read X
if (X >= a) then
{
read Y
X = X - a
Y = Y + a
write X
write Y
}
end transaction
OSes: 5. Synch
(VUW CS 305)
<Ti, start>
<Ti, X, oldV, newV>
<Ti, Y, oldV, newV>
<Ti, commit>
81
Recovery
Operations:
– undo( Transactioni )
– redo( Transactioni )
Possible
states of Transactioni
– committed, but were new values written?
– aborted, but were old values restored?
– unfinished
OSes: 5. Synch
82
10.2. Checkpoints
A checkpoint
fixes state changes by writing
them to stable storage so that the log file
can be reset or shortened.
OSes: 5. Synch
83
10.3. Concurrent Atomic Transactions
We
want to ensure that the outcome of
concurrent transactions are the same as if
they were executed in some serial order
– serializability
OSes: 5. Synch
84
A Serial Schedule
Transaction
0
Fig. 6.23, p.195
Transaction 1
read A
write A
read B
write B
read A
write A
read B
write B
OSes: 5. Synch
85
Conflicting Operations
Two
operations in different transactions
conflict if they access the same data and one
of them is a write.
Serializability
must avoid conflicting
operations:
– it can do that by delaying/speeding up when
operations in a transaction are performed
OSes: 5. Synch
86
A Concurrent Serializable Schedule
Fig. 6.24, p.196
Transaction
0
Transaction 1
read A
write A
read A
write A
read B
write B
read B
write B
OSes: 5. Synch
87
10.4. Locks
Serializability
can be achieved by locking
data items
There
are a range of locking modes:
– a shared lock allows multiple reads by
different transactions
– an exclusive lock allows only one transaction
to do reads/writes
OSes: 5. Synch
88
10.5. Timestamping
One
way of ordering transactions
Using
the system clock is not sufficient
when transactions may originate on
different machines
OSes: 5. Synch
89
© Copyright 2026 Paperzz