Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
Process Synchronization
Background
Peterson’s Solution
Synchronization Hardware
Semaphores
while (true) {
while (counter == 0)
; // do nothing
nextConsumed = buffer[out];
out = (out + 1) % BUFFER_SIZE;
counter- -;
register1 = counter
register1 = register1 + 1
counter = register1
counter - -; could be implemented in machine language as:
register2 = counter
register2 = register2 - 1
counter = register2
Consider this execution interleaving with “counter = 5” initially:
T0: producer execute register1 = counter {register1 = 5}
T1: producer execute register1 = register1 + 1 {register1 = 6}
T2: consumer execute register2 = counter {register2 = 5}
T3: consumer execute register2 = register2 - 1 {register2 = 4}
T4: producer execute counter = register1 {counter = 6 }
T5: consumer execute counter = register2 {counter = 4}
• Now we have arrived at the incorrect state “counter ==4”
Race Condition
do {
flag[i] = TRUE;
turn = j;
while (flag[j] && turn == j);
critical section
flag[i] = FALSE;
remainder section
} while (TRUE);
Provable that
1. Mutual exclusion is preserved
2. Progress requirement is satisfied
3. Bounded-waiting requirement is met
Synchronization Hardware
We have just described one software-based solution to the
critical-section problem
In general, we can state that any solution to the critical-section
problem requires a simple tool—a lock
Race conditions are prevented by requiring that critical regions
be protected by locks
A process must acquire a lock before entering a critical section;
it releases the lock when it exits the critical section
Solution to Critical-section Problem Using Locks
do {
acquire lock
critical section
release lock
remainder section
} while (TRUE);
Analyze this
Does this scheme provide mutual exclusion?
Process 1 lock = 0 Process 2
While(1){ While(1){
while (lock != 0); while (lock != 0);
lock = 1; //Lock lock = 1; //Lock
critical section critical section
lock = 0; //Unlock lock = 0; //Unlock
other code other code
} }
No
lock = 0;
P1 : while (lock != 0); //Context switch
P2 : while (lock != 0);
P2 : lock = 1; //Context switch
P1 : lock = 1;
…….Both processes in critical section
Analyze this
Process 1
Make atomic
While(1){
while (lock != 0);
lock = 1; //Lock
critical section
lock = 0; //Unlock
other code
}
Synchronization Hardware (Contd..)
Many systems provide hardware support for critical section code
Uniprocessors: We could prevent interrupts from occurring
while a shared variable is being modified.
Currently running code would execute without preemption
Generally too inefficient on multiprocessor systems
Disabling interrupts on a multiprocessor can be time consuming.
Many modern computer systems therefore provide special hardware
instructions that allow us either to test and modify the content of a
word or to swap the contents of two words atomically
Atomic = Uninterruptible
Hardware Support: TestAndSet Instruction
Write to a memory location, return its old value
Definition:
boolean TestAndSet (boolean *target) Memory
{
Processor
boolean rv = *target; 1
*target = TRUE;
return rv: 0
} Target
(Old value=0)
(The entire function is executed atomically)
Why does this work? If two CPUs execute TestAndSet at the same
time, the hardware ensures that one TestAndSet does both its
steps before the other one starts
Solution using TestAndSet
Shared boolean variable lock, initialized to FALSE
Solution: The structure of process Pi
do {
while (TestAndSet (&lock ))
; // do nothing
// critical section
lock = FALSE;
// remainder section
} while (TRUE);
The first invocation of TestAndSet will read a FALSE and set lock to
TRUE and return. The second TestAndSet invocation will then see
lock as TRUE, and will loop continuously until lock becomes FALSE
Hardware Support: Swap Instruction
Definition:
void Swap (boolean *a, boolean *b)
{
boolean temp = *a;
*a = *b;
*b = temp:
}
(The entire function is executed atomically)
Why does this work? If two CPUs execute Swap at the same time,
the hardware ensures that one Swap completes, only then the
second Swap starts
Solution using Swap
Shared Boolean variable lock initialized to FALSE; each process has
a local Boolean variable key
Solution: The structure of process Pi
do {
key = TRUE;
while ( key == TRUE)
Swap (&lock, &key );
// critical section
lock = FALSE;
// remainder section
} while (TRUE);
Semaphore
Synchronization tool
Semaphore S – integer variable
Two standard operations modify S: wait() and signal()
Originally called P() (“to test”) and V() (“to increment”)
Less complicated
Can only be accessed via two atomic operations
wait (S) {
while S <= 0
; // no-op
S--;
}
signal (S) {
S++;
}
Semaphore as General Synchronization Tool
Counting semaphore – integer value can range over an unrestricted domain
Binary semaphore – integer value can range only between 0 and 1; can be
simpler to implement
Also known as mutex locks
We can implement a counting semaphore S as a binary semaphore
Provides mutual exclusion among multiple processes
Suppose n processes share a semaphore, mutex, initialized to 1. Here, each process
Pi is organized as below:
Semaphore mutex; // initialized to 1
do {
wait (mutex);
// Critical Section
signal (mutex);
// remainder section
} while (TRUE);
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(semaphore *S) {
S->value--;
if (S->value < 0) {
add this process to S->list;
block();
}
}
Implementation of signal:
signal(semaphore *S) {
S->value++;
if (S->value <= 0) {
remove a process P from S->list;
wakeup(P);
}
}
Deadlock and Starvation
Bounded-Buffer Problem
Dining-Philosophers Problem
Bounded-Buffer Problem
N buffers, each can hold one item
do {
………..
// produce an item in nextp
………..
wait (empty);
wait (mutex);
………….
// add the item 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 nextc
…………
signal (mutex);
signal (empty);
………….
// consume the item in nextc
…………
} while (TRUE);
Readers-Writers Problem
A database is shared among a number of concurrent processes
Readers – only read the database; they do not perform any updates
Writers – can both read and write
Shared Data
Database
Semaphore mutex initialized to 1
Semaphore wrt initialized to 1
Integer readcount initialized to 0
Readers-Writers Problem Variations
do {
wait (wrt) ;
………..
// writing is performed
…………
signal (wrt) ;
} while (TRUE);
Readers-Writers Problem (Cont.)
The structure of a reader process
do {
wait (mutex) ;
readcount ++ ;
if (readcount == 1)
wait (wrt) ;
signal (mutex)
………….
// reading is performed
………….
wait (mutex) ;
readcount - - ;
if (readcount == 0)
signal (wrt) ;
signal (mutex) ;
} while (TRUE);
Dining-Philosophers Problem
do {
wait ( chopstick[i] );
wait ( chopStick[ (i + 1) % 5] );
// eat
signal ( chopstick[i] );
signal (chopstick[ (i + 1) % 5] );
// think
} while (TRUE);