Module 4 - Chapter 6 Process Synchronization
Module 4 - Chapter 6 Process Synchronization
Synchronization
Process Synchronization
• Background
• The Critical-Section Problem
• Peterson’s Solution
• Synchronization Hardware
• Semaphores
• Classic Problems of
Synchronization
• Monitors
• Synchronization Examples
• Atomic Transactions
Cooperating Processes
• Independent process cannot affect or be
affected by the execution of another process
• Cooperating process can affect or be affected
by the execution of another process
• Advantages of process cooperation
– Information sharing
– Computation speed-up
– Modularity
– Convenience
Producer-Consumer Problem
• Paradigm for cooperating processes,
producer process produces
information that is consumed by a
consumer process
– unbounded-buffer places no practical
limit on the size of the buffer
– bounded-buffer assumes that there is a
fixed buffer size
Bounded-Buffer – Shared-Memory Solution
• Shared data
#define BUFFER_SIZE 10
Typedef struct {
...
} item;
item buffer[BUFFER_SIZE];
int in = 0;
int out = 0;
• Solution is correct, but can only use
BUFFER_SIZE-1 elements
Bounded-Buffer – Insert() Method
while (true) {
/* Produce an item */
while (((in = (in + 1) % BUFFER SIZE count) == out)
; /* do nothing -- no free buffers */
buffer[in] = item;
in = (in + 1) % BUFFER SIZE;
{
Bounded Buffer – Remove() Method
while (true) {
while (in == out)
; // do nothing -- nothing to
consume
register1 = count
register1 = register1 + 1
count = register1
• count-- could be implemented as
register2 = count
register2 = register2 - 1
count = register2
• Consider this execution interleaving with “count = 5” initially:
S0: producer execute register1 = count {register1 = 5}
S1: producer execute register1 = register1 + 1 {register1 = 6}
S2: consumer execute register2 = count {register2 = 5}
S3: consumer execute register2 = register2 - 1 {register2 = 4}
S4: producer execute count = register1 {count = 6 }
S5: consumer execute count = register2 {count = 4}
PROCESS SYNCHRONIZATION Critical Sections
Critical Section Code in which only one process can execute at any one
time.
CRITICAL SECTION
flag[i] = FALSE;
REMAINDER SECTION
}
Synchronization Hardware
• Many systems provide hardware support for critical
section code
• Uniprocessors – could disable interrupts
– Currently running code would execute without
preemption
– Generally too inefficient on multiprocessor systems
• Operating systems using this not broadly scalable
• Modern machines provide special atomic hardware
instructions
• Atomic = non-interruptable
– Either test memory word and set value
– Or swap contents of two memory words
TestAndSet Instruction
• Definition:
while (true) {
while ( TestAndSet (&lock ))
; /* do nothing
// critical section
lock = FALSE;
// remainder section
}
Swap Instruction
• Definition:
// critical section
lock = FALSE;
// remainder section
}
Semaphore
• Synchronization tool that does not require busy waiting
• Semaphore S – integer variable
• Two standard operations modify S: wait() and signal()
– wait (S) {
while S <= 0
; // no-op
S--;
}
– signal (S) {
S++;
}
Semaphore as General Synchronization Tool
• 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); }
}
Deadlock and Starvation
• Deadlock – two or more processes are waiting indefinitely for an event
that can be caused by only one of the waiting processes
• Let S and Q be two semaphores initialized to 1
P0 P1
wait (S); wait (Q);
wait (Q); wait (S);
. .
. .
. .
signal (S); signal (Q);
signal (Q); signal (S);
• Starvation – indefinite blocking. A process may never be removed from
the semaphore queue in which it is suspended.
Classical Problems of
Synchronization
• Bounded-Buffer Problem
• Readers and Writers Problem
• Dining-Philosophers Problem
Bounded-Buffer Problem
• N buffers, each can hold one item
• Semaphore mutex initialized to the
value 1
• Semaphore full initialized to the
value 0
• Semaphore empty initialized to the
value N.
Bounded Buffer Problem (Cont.)
• The structure of the producer process
while (true) {
// produce an item
wait (empty);
wait (mutex);
signal (mutex);
signal (full);
}
Bounded Buffer Problem (Cont.)
• The structure of the consumer process
while (true) {
wait (full);
wait (mutex);
signal (mutex);
signal (empty);
}
Readers-Writers Problem
• A data set is shared among a number of concurrent processes
– Readers – only read the data set; they do not perform any
updates
– Writers – can both read and write.
• Shared Data
– Data set
– Semaphore mutex initialized to 1.
– Semaphore wrt initialized to 1.
– Integer readcount initialized to 0.
Readers-Writers Problem (Cont.)
• The structure of a writer process
while (true) {
wait (wrt) ;
// writing is performed
signal (wrt) ;
}
Readers-Writers Problem (Cont.)
• The structure of a reader process
while (true) {
wait (mutex) ;
readcount ++ ;
if (readercount == 1) wait (wrt) ;
signal (mutex)
// reading is performed
wait (mutex) ;
readcount - - ;
if (redacount == 0) signal (wrt) ;
signal (mutex) ;
}
Dining-Philosophers Problem
• Shared data
– Bowl of rice (data set)
– Semaphore chopstick [5] initialized to 1
Dining-Philosophers Problem
•
(Cont.)
The structure of Philosopher i:
While (true) {
wait ( chopstick[i] );
wait ( chopStick[ (i + 1) % 5] );
// eat
signal ( chopstick[i] );
signal (chopstick[ (i + 1) % 5] );
// think
}
Problems with Semaphores
• Correct use of semaphore operations:
monitor monitor-name
{
// shared variable declarations
procedure P1 (…) { …. }
…
monitor DP
{
enum { THINKING; HUNGRY, EATING) state [5] ;
condition self [5];
initialization_code() {
for (int i = 0; i < 5; i++)
state[i] = THINKING;
}
}
Solution to Dining Philosophers (cont)
dp.pickup (i)
EAT
dp.putdown (i)
Monitor Implementation Using Semaphores
• Variables
semaphore mutex; // (initially = 1)
semaphore next; // (initially = 0)
int next-count = 0;
wait(mutex);
…
body of F;
…
if (next-count > 0)
signal(next)
else
signal(mutex);
x-count++;
if (next-count > 0)
signal(next);
else
signal(mutex);
wait(x-sem);
x-count--;
Monitor Implementation
• The operation x.signal can be implemented as:
if (x-count > 0) {
next-count++;
signal(x-sem);
wait(next);
next-count--;
}