ch6: Operating System Process Synchronization
ch6: Operating System Process Synchronization
Outline
Background
The Critical-Section Problem
Peterson’s Solution
Mutex Locks
Semaphores
Monitors
Evaluation
Objectives
Describe the critical-section problem and illustrate a race
condition
Illustrate hardware solutions to the critical-section
problem using memory barriers, compare-and-swap
operations, and atomic variables
Demonstrate how mutex locks, semaphores, monitors, and
condition variables can be used to solve the critical
section problem
Evaluate tools that solve the critical-section problem in
low-, Moderate-, and high-contention scenarios
Background
Processes can execute concurrently
May be interrupted at any time, partially completing execution
Concurrent access to shared data may result in data inconsistency
Maintaining data consistency requires mechanisms to ensure the orderly
execution of cooperating processes
We illustrated in chapter 4 the problem when we considered the
Bounded Buffer problem with use of a counter that is updated
concurrently by the producer and consumer,. Which lead to race
condition.
Producer consumer using counter
Count++
in machine language
Count--
in machine language
Race condition
Race Condition
Processes P0 and P1 are creating child processes using the fork() system call
Race condition on kernel variable next_available_pid which represents
the next available process identifier (pid)
turn = j; turn = i;
} }
Correctness of the Software Solution
} }
Correctness of Peterson’s Solution
100
Modern Architecture Example (Cont.)
However, since the variables flag and x are independent of each
other, the instructions:
flag = true;
x = 100;
while (true) {
acquire lock
critical
section
release lock
remainder section
}
while (true) {
acquire lock
critical
section
release lock
Semaphore
Synchronization tool that provides more sophisticated ways (than Mutex
locks) for processes to synchronize their activities.
Semaphore S – integer variable
Can only be accessed via two indivisible (atomic) operations
wait() and signal()
Originally called P() and V()
Definition of the wait() operation
wait(S) {
while (S <= 0)
; // busy wait
S--;
}
Definition of the signal() operation
signal(S) {
S++;
}
Semaphore (Cont.)
Consider P1 and P2 that with two statements S1 and S2 Definition of the wait() operation
and the requirement that S1 to happen before S2
wait(S) {
Create a semaphore “synch” initialized to 0
while (S <= 0)
P1:
; // busy wait
S1;
S--;
signal(synch);
}
P2:
Definition of the signal() operation
wait(synch);
S2; signal(S) {
S++;
}
Semaphore Implementation
Must guarantee that no two processes can execute the wait() and
signal() on the same semaphore at the same time
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
Waiting queue
typedef struct {
int value;
struct process *list;
} semaphore;
Implementation with no Busy waiting (Cont.)
wait(semaphore *S) {
S->value--;
if (S->value < 0) {
add this process to S->list;
block();
}
}
signal(semaphore *S) {
S->value++;
if (S->value <= 0) {
remove a process P from S->list;
wakeup(P);
}
}
Liveness
Processes may have to wait indefinitely while trying to acquire a synchronization tool such
as a mutex lock or semaphore.
Waiting indefinitely violates the progress and bounded-waiting criteria discussed at the
beginning of this chapter.
Liveness refers to a set of properties that a system must satisfy to ensure processes make
progress.
Indefinite waiting is an example of a liveness failure.
Liveness
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 Definition of the wait() operation
P0 P1 wait(S) {
wait(S); wait(Q); while (S <= 0)
wait(Q); wait(S); ; // busy wait
... ... S--;
signal(S); signal(Q); }
signal(Q); signal(S); Definition of the signal() operation
signal(S) {
Consider if P0 executes wait(S) and P1 wait(Q). When P0 executes S++;
wait(Q), it must wait until P1 executes signal(Q) }
However, P1 is waiting until P0 execute signal(S).
Since these signal() operations will never be executed, P0 and P1 are
deadlocked.
Liveness
Other forms of deadlock:
Starvation – indefinite blocking
A process may never be removed from the semaphore queue in which it is
suspended
Priority Inversion – Scheduling problem when lower-priority process holds
a lock needed by higher-priority process
Solved via priority-inheritance protocol