Ch07 Process Synchronization
description
Transcript of Ch07 Process Synchronization
Course 7: Synchronization
6.2 Silberschatz, Galvin and GagneOperating System Concepts – 8th Edition
Course 6: Review Concurrency: multiprocessing, multitasking, or any
combination
Race condition: the situation that the result of a
concurrent execution is dependent on the
nondeterministic interleaving
Atomic instructions: its execution cannot be
interleaved with other instructions before its completion
Synchronization – mechanism by which processes
communicate with each other in order to agree on a
sequence of actions
Synchronization requirements – ex: dinning
philosophers
Mutual exclusion
No deadlocks
Starvation free
Critical section - piece of code that only one thread
can execute at once.
6.3 Silberschatz, Galvin and GagneOperating System Concepts – 8th Edition
Course 6: Review
6.4 Silberschatz, Galvin and GagneOperating System Concepts – 8th Edition
Course 6: Review
Ex: Too much milk
problem
6.5 Silberschatz, Galvin and GagneOperating System Concepts – 8th Edition
Course 7: Thread Synchronization
Peterson solution
Locks
Hardware locks
Higher level solutions
Semaphores
Monitors and condition variables
6.6 Silberschatz, Galvin and GagneOperating System Concepts – 8th Edition
Peterson solution
6.7 Silberschatz, Galvin and GagneOperating System Concepts – 8th Edition
Peterson solution
Peterson:
6.8 Silberschatz, Galvin and GagneOperating System Concepts – 8th Edition
Peterson solution - proof
Peterson’s algorithm combines the ideas of solution attempts II and III; If both
processes have set their enter-flag to true, then the value of turn decides who may
enter the critical section
Peterson’s algorithm satisfies mutual exclusion, proof:
Assume that both P1 and P2 are in their critical section and that P1 entered before P2
When P1 entered the critical section we have enter1 =true, and P2 must thus have seen turn
= 2 upon entering its critical section
P2 could not have executed line 2 after P1 entered, as this sets turn = 1 and would have
excluded P2, as P1 does not change turn while being in the critical section
However, P2 could not have executed line 2 before P1 entered either because then P1 would
have seen enter2 =true and turn = 1, although P2 should have seen turn = 2
6.9 Silberschatz, Galvin and GagneOperating System Concepts – 8th Edition
Peterson solution - proof
Peterson’s algorithm is starvation free, proof:
Assume P1 is forced to wait in the entry protocol forever. P2 can
eventually do only one of three actions:
1. Be in its non-critical section: then enter2 is false, thus allowing P1
to enter.
2. Wait forever in its entry protocol: impossible because turn cannot
be both 1 and 2
3. Repeatedly cycle through its code: then P2 will set turn to 1 at
some point and never change it back
6.10 Silberschatz, Galvin and GagneOperating System Concepts – 8th Edition
Peterson solution - conclusions Peterson solution works, but it’s really unsatisfactory
Really complex – even for this simple an example
Hard to convince yourself that this really works
While P1/P2 is waiting, it is consuming CPU time
This is called “busy-waiting”
There’s a better way
Have hardware provide better (higher-level) primitives than atomic load and store
Build even higher-level programming abstractions on this new hardware support
6.11 Silberschatz, Galvin and GagneOperating System Concepts – 8th Edition
Synchronization solutions
We are going to implement various higher-level synchronization primitives
using atomic operations
Everything is pretty painful if only atomic primitives are load and store
Need to provide primitives useful at user-level
6.12 Silberschatz, Galvin and GagneOperating System Concepts – 8th Edition
Locks
6.13 Silberschatz, Galvin and GagneOperating System Concepts – 8th Edition
Locks Suppose we have some sort of implementation of a lock (more in a
moment).
Lock.Acquire() – wait until lock is free, then grab
Lock.Release() – Unlock, waking up anyone waiting
These must be atomic operations – if two threads are waiting for the lock and both see it’s free, only one succeeds to grab the lock
Then, our “milk problem” is easy:
milklock.Acquire();
if (nomilk)
buy milk;
milklock.Release();
Once again, section of code between Acquire() and Release() called a “Critical Section”
6.14 Silberschatz, Galvin and GagneOperating System Concepts – 8th Edition
Interrupt Enable/Disable How can we build multi-instruction atomic operations?
Recall: dispatcher gets control in two ways.
Internal: Thread does something to relinquish the CPU
External: Interrupts cause dispatcher to take CPU
On a uniprocessor, can avoid context-switching by:
Avoiding internal events
Preventing external events by disabling interrupts
Consequently, naïve Implementation of locks:
LockAcquire { disable Ints; }
LockRelease { enable Ints; }
Problems with this approach:
Can’t let user do this! Consider following:LockAcquire();While(TRUE) {;}
Real-Time system—no guarantees on timing!
Critical Sections might be arbitrarily long
What happens with I/O or other important events?
“Reactor about to meltdown. Help?”
6.15 Silberschatz, Galvin and GagneOperating System Concepts – 8th Edition
Better Implementation of Locks by
Disabling Interrupts
Key idea: maintain a lock variable and impose mutual exclusion only during operations on that variable
int value = FREE;
Acquire() {
disable interrupts;
if (value == BUSY) {
put thread on wait queue;
Go to sleep();
// Enable interrupts?
} else {
value = BUSY;
}
enable interrupts;
}
Release() {
disable interrupts;
if (anyone on wait queue) {
take thread off wait queue
Place on ready queue;
} else {
value = FREE;
}
enable interrupts;
}
6.16 Silberschatz, Galvin and GagneOperating System Concepts – 8th Edition
Better Implementation of Locks by
Disabling Interrupts
Note: unlike previous solution, the critical section (inside Acquire()) is very short
User of lock can take as long as they like in their own critical section: doesn’t impact global machine behavior
Critical interrupts taken in time!
int value = FREE;
Acquire() {
disable interrupts;
if (value == BUSY) {
put thread on wait queue;
enable interrupts;
Go to sleep();
} else {
value = BUSY;
}
enable interrupts;
}
6.17 Silberschatz, Galvin and GagneOperating System Concepts – 8th Edition
Disabling Interrupts conclusions
Problems with previous solution:
Can’t give lock implementation to users
Doesn’t work well on multiprocessor
Disabling interrupts on all processors requires messages
and would be very time consuming
Alternative: atomic instruction sequences
These instructions read a value from memory and write a new
value atomically
Hardware is responsible for implementing this correctly
on both uniprocessors (not too hard)
and multiprocessors (requires help from cache coherence
protocol)
Unlike disabling interrupts, can be used on both uniprocessors
and multiprocessors
6.18 Silberschatz, Galvin and GagneOperating System Concepts – 8th Edition
Hardware Locks
6.19 Silberschatz, Galvin and GagneOperating System Concepts – 8th Edition
Read-Modify-Write Sequences
test&set (&address) { /* most architectures */result = M[address];M[address] = 1;return result;
}
swap (&address, register) { /* x86 */temp = M[address];M[address] = register;register = temp;
}
6.20 Silberschatz, Galvin and GagneOperating System Concepts – 8th Edition
Read-Modify-Write Sequences
test&set (&address) { /* most architectures */result = M[address];M[address] = 1;return result;
}
int value = 0; // Free
Acquire() {
while (test&set(value)); // while busy
}
//Critical section
Release() {
value = 0;
}
Simple explanation:
If lock is free, test&set reads 0 and sets value=1, so lock is now busy.
It returns 0 so while exits.
If lock is busy, test&set reads 1 and sets value=1 (no change). It
returns 1, so while loop continues
When we set value = 0, someone else can get lock
Busy-Waiting: thread consumes cycles while waiting
6.21 Silberschatz, Galvin and GagneOperating System Concepts – 8th Edition
Read-Modify-Write Sequences
Positives for this solution
Machine can receive interrupts
User code can use this lock
Works on a multiprocessor
Negatives
This is very inefficient because the busy-waiting thread will consume cycles waiting
Waiting thread may take cycles away from thread holding lock (no one wins!)
Priority Inversion: If busy-waiting thread has higher priority than thread holding lock no progress!
Priority Inversion problem with original Martian rover
End of Course 7