2-3-Process Sync-1
2-3-Process Sync-1
Ms.S.Rajalaksh
mi,
AP,
SSNCE
Process Synchronization
● Background
● The Critical-Section Problem
● Peterson’s Solution
● Synchronization Hardware
● Mutex Locks
● Semaphores
● Classic Problems of Synchronization
● Monitors
● Synchronization Examples
● Alternative Approaches
Course Objectives / Outcomes
while (true) {
/* produce an item in next produced */
while (true) {
while (counter == 0)
; /* do nothing */
next_consumed = buffer[out];
out = (out + 1) % BUFFER_SIZE;
counter--;
/* consume the item in next consumed */
}
Race Condition
(OR)
consumer: counter = register2 (counter = 4)
producer: counter = register1 (counter = 6)
◻ The value of counter may be either 4 or 6, where the correct result should
be 5.
Critical Section Problem
● Consider system of n processes {p0, p1, … pn-1}
● Each process has critical section segment of code
● Process may be changing common variables, updating
table, writing file, etc
● When one process in critical section, no other may be in its
critical section
● Critical section problem is to design protocol to solve this
● Each process must ask permission to enter critical section in
entry section, may follow critical section with exit section,
then remainder section
Critical Section
● Test cases
● P0 WTE first
● P1 WTE first
● P0 Enters, P1 WTE, P1 WTE again
● P0 and P1 WTE at the same time
Algorithm 2 - Dekkers Algorithm
General Structure of Process Pj
do {
● Shared variables flag[ j ] := true; // express its wish
while (flag[ i ] == true) ; //waiting
● Boolean flag[2]; critical section
flag [j] = false; // give chance to
initially flag [0] = flag [1] = false. other process
remainder section
● flag [i] = true ⇒ Pi ready to enter its } while (1);
critical section
● General Structure of Process Pi
do {
flag[ i ] := true; // express its wish
while (flag[ j ]==true) ; //waiting
critical section
flag [i] = false; // give chance to other process
remainder section
} while (1);
Algorithm 2 – Contd.,
● Satisfies mutual exclusion but not progress
● If p0 and p1 sets flag to be true at same time, then deadlock (both
processes will wait for each other to finish)
● Changing the order of while and setting the flag statements will not
guarantee mutual exclusion.(both will be in the CS at the same time)
● while (flag[ j ]);
● flag[ i ]=true; ------------- No Mutual Exclusion
Algorithm 3- Peterson’s Solution
● Good algorithmic description of solving the problem
● Two process solution
● Assume that the load and store machine-language
instructions are atomic; that is, cannot be interrupted
● The two processes share two variables:
● int turn;
● Boolean flag[2]
do {
acquire lock
critical section
release lock
remainder section
} while (TRUE);
test_and_set Instruction
Definition:
boolean test_and_set (boolean *lock)
{
boolean oldvalue = *lock;
*lock = TRUE;
return oldvalue:
}
1. Executed atomically
2. Returns the original value of passed parameter
3. Set the new value of passed parameter to “TRUE”.
Solution using test_and_set()
if (*lock == expected_false)
*lock = new_value_true;
return temp;
}
1. Executed atomically
2. Returns the original value of passed parameter “lock”
3. Set the variable “lock” the value of the passed parameter “new_value(true)” but
only if “lock” ==“expected(false)”. That is, the swap takes place only under this
condition.
Solution using compare_and_swap
● Shared integer “lock” initialized to 0;
● Solution:
do {
while (compare_and_swap(&lock, 0, 1) != 0)
; /* do nothing */
/* critical section */
lock = 0;
/* remainder section */
} while (true);
Mutex Locks
● Previous solutions are complicated and generally inaccessible
to application programmers
● OS designers build software tools to solve critical section
problem
● Simplest is mutex lock
● Protect a critical section by first acquire() a lock then
release() the lock
● Boolean variable indicating if lock is available or not
● Calls to acquire() and release() must be atomic
● Usually implemented via hardware atomic instructions
● But this solution requires busy waiting
● This lock therefore called a spinlock
acquire() and release()
● acquire() {
while (!available)
; /* busy wait */
available = false;;
}
● release() {
available = true;
}
● do {
acquire lock
critical section
release lock
remainder section
} while (true);
Semaphore
● Synchronization tool that provides more sophisticated ways (than Mutex locks)
for process to synchronize their activities.
● Semaphore S – integer variable S =1 (free)
● Can only be accessed via two indivisible (atomic) operations
● wait() and signal()
4 Originally called P() and V()
wait(semaphore *S) {
typedef struct{
S->value--;
int value;
if (S->value < 0) { struct process *list;
add this process to S->list;
} semaphore;
block();
}
} S->value =1 (free)
signal(semaphore *S) {
S->value++;
if (S->value <= 0) {
remove a process P from S->list;
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);
do {
...
/* produce an item in next_produced */
...
wait(empty);
wait(mutex);
...
/* add next produced to the buffer */
...
signal(mutex);
signal(full);
} while (true);
Bounded Buffer Problem (Cont.)
● The structure of the consumer process
Do {
wait(full);
wait(mutex);
...
/* remove an item from buffer to next_consumed */
...
signal(mutex);
signal(empty);
...
/* consume the item in next consumed */
...
} while (true);
Implementation with no Busy waiting (Cont.)
wait(semaphore *S) {
typedef struct{
S->value--;
int value;
if (S->value < 0) { struct process *list;
add this process to S->list;
} semaphore;
block();
}
} S->value =1 (free)
signal(semaphore *S) {
S->value++;
if (S->value <= 0) {
remove a process P from S->list;
wakeup(P);
}
}
Bounded buffer problem – Test cases
● Buffer size =3
● Consumer runs first and then Producer
runs and produces first item
● P runs first and then C runs
● P runs 4 times and fills all items. Then C
runs
● When both P and C runs simultaneously.
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
● Problem – allow multiple readers to read at the same time
● Only one single writer can access the shared data at the same time
● Several variations of how readers and writers are considered – all
involve some form of priorities
● Shared Data
● Data set
● Semaphore rw_mutex initialized to 1 // to access <CS>
● Semaphore mutex initialized to 1 // to access shared data
“readcount” by multiple reader process
● Integer read_count initialized to 0
Readers-Writers Problem (Cont.)
do {
wait(rw_mutex);
...
/* writing is performed */
...
signal(rw_mutex);
} while (true);
Readers-Writers Problem (Cont.)
● The structure of a reader process
do {
wait(mutex);
read_count++;
if (read_count == 1)
wait(rw_mutex);
signal(mutex);
...
/* reading is performed */
...
wait(mutex);
read count--;
if (read_count == 0)
signal(rw_mutex);
signal(mutex);
} while (true);
Readers-Writers Problem Variations
// eat
signal (chopstick[i] );
signal (chopstick[ (i + 1) % 5] );
// think
} while (TRUE);
● What is the problem with this algorithm?
Dining-Philosophers Problem Algorithm (Cont.)
● Deadlock handling
● Allow at most 4 philosophers to be sitting
simultaneously at the table.
● Allow a philosopher to pick up the forks only if both
are available (picking must be done in a critical
section.
● Use an asymmetric solution -- an odd-numbered
philosopher picks up first the left chopstick and then
the right chopstick. Even-numbered philosopher
picks up first the right chopstick and then the left
chopstick.
Problems with Semaphores
monitor monitor-name
{
// shared variable declarations
procedure P1 (…) { …. }
● condition x, y;
● Two operations are allowed on a condition variable:
● x.wait() – a process that invokes the operation is
suspended until x.signal()
● x.signal() – resumes one of processes (if any) that
invoked x.wait()
4 If no x.wait() on the variable, then it has no effect on
the variable
Monitor with Condition Variables
Condition Variables Choices
initialization_code() {
for (int i = 0; i < 5; i++)
state[i] = THINKING;
}
}
Solution to Dining Philosophers (Cont.)
DiningPhilosophers.pickup(i);
EAT
DiningPhilosophers.putdown(i);
● Solaris
● Windows
● Linux
● Pthreads
Solaris Synchronization
● Implements a variety of locks to support multitasking, multithreading
(including real-time threads), and multiprocessing
● Uses adaptive mutexes for efficiency when protecting data from
short code segments
● Starts as a standard semaphore spin-lock
● If lock held, and by a thread running on another CPU, spins
● If lock held by non-run-state thread, block and sleep waiting for signal of
lock being released
● Uses condition variables
● Uses readers-writers locks when longer sections of code need
access to data
● Uses turnstiles to order the list of threads waiting to acquire either an
adaptive mutex or reader-writer lock
● Turnstiles are per-lock-holding-thread, not per-object
● Priority-inheritance per-turnstile gives the running thread the highest
of the priorities of the threads in its turnstile
Windows Synchronization