Chapter 5
Chapter 5
2
• Process synchronization
– What is the problem?
– Criteria for solution
– Producer / consumer example
• Commitment
– Compile and run semaphore code from os-book.com
Peterson’s solution
… to the 2-process producer/consumer problem. (p. 204)
while (true)
{
ready[ me ] = true
turn = other
while (ready[ other ] && turn == other) ;
Do critical section
ready[ me ] = false
Do non-critical code
}
// Don’t memorize but think: Why does this ensure mutual exclusion?
// What assumptions does this solution make?
HW support
• As we mentioned before, we can disable interrupts
– No one can preempt me.
– Disadvantages
acquire() release()
{ {
if (value <= 0) ++value
wait/sleep // wake sleeper
--value }
}
Deadlock / starvation
• After we solve a mutual exclusion problem, also need to
avoid other problems
– Another way of expressing our synchronization goals
mutex.release();
mutex.release();
empty.release();
full.release();
}
}
// READ NOW
mutex.acquire();
--readerCount;
if(readerCount == 0)
db.release();
mutex.release();
Example output
writer 0 wants to write.
writer 0 is writing.
writer 0 is done writing.
reader 2 wants to read.
writer 1 wants to write.
reader 0 wants to read.
reader 1 wants to read.
Reader 2 is reading. Reader count = 1
Reader 0 is reading. Reader count = 2
Reader 1 is reading. Reader count = 3
writer 0 wants to write.
Reader 1 is done reading. Reader count = 2
Reader 2 is done reading. Reader count = 1
Reader 0 is done reading. Reader count = 0
writer 1 is writing.
reader 0 wants to read.
writer 1 is done writing.
CS 346 – Sect. 5.7-5.8
• Process synchronization
– “Dining philosophers” (Dijkstra, 1965)
– Monitors
Dining philosophers
• Classic OS problem
– Many possible solutions depending on how foolproof you want
solution to be
• Simulates synchronization situation of several resources,
and several potential consumers.
• What is the problem?
• Model chopsticks with semaphores – available or not.
– Initialize each to be 1
• Achieve mutual exclusion:
– acquire left and right chopsticks (numbered i and i+1)
– Eat
– release left and right chopsticks
• What could go wrong?
DP (2)
• What can we say about this solution?
mutex.acquire();
Acquire 2 neighboring forks
Eat
Release the 2 forks
mutex.release();
• Other improvements:
– Ability to see if either neighbor is eating
– May make more sense to associate semaphore with the
philosophers, not the forks. A philosopher should block if cannot
acquire both forks.
– When done eating, wake up either neighbor if necessary.
Monitor
• Higher level than semaphore
– Semaphore coding can be buggy
• Programming language construct
– Special kind of class / data type
– Hides implementation detail
• Automatically ensures mutual exclusion
– Only 1 thread may be “inside” monitor at any one time
– Attributes of monitor are the shared variables
– Methods in monitor deal with specific synchronization problem.
This is where you access shared variables.
– Constructor can initialize shared variables
• Supported by a number of HLLs
– Concurrent Pascal, Java, C#
Condition variables
• With a monitor, you get mutual exclusion
• If you also want to ensure against deadlock or starvation,
you need condition variables
• Special data type associated with monitors
• Declared with other shared attributes of monitor
• How to use them:
– No attribute value to manipulate. 2 functions only:
– Wait: if you call this, you go to sleep. (Enter a queue)
– Signal: means you release a resource, waking up a thread
waiting for it.
– Each condition variable has its own queue of waiting
threads/processes.
Signal( )
• A subtle issue for signal…
• In a monitor, only 1 thread may be running at a time.
• Suppose P calls x.wait( ). It’s now asleep.
• Later, Q calls x.signal( ) in order to yield resource to
P.
• What should happen? 3 design alternatives:
– “blocking signal” – Q immediately goes to sleep so that P can
continue.
– “nonblocking signal” – P does not actually resume until Q has left
the monitor
– Compromise – Q immediately exits the monitor.
• Whoever gets to continue running may have to go to
sleep on another condition variable.
CS 346 – Sect. 5.9
• Process synchronization
– “Dining philosophers” monitor solution
– Java synchronization
– atomic operations
Monitor for DP
• Figure 5.18 on page 228
• Shared variable attributes:
– state for each philosopher
– “self” condition variable for each philosopher
• takeForks( )
– Declare myself hungry
– See if I can get the forks. If not, go to sleep.
• returnForks( )
– Why do we call test( )?
• test( )
– If I’m hungry and my neighbors are not eating, then I will eat and
leave the monitor.
Synch in Java
• “thread safe” = data remain consistent even if we have
concurrently running threads
• Semaphore class
– acquire( ) and release( )
Atomic operations
• Behind the scenes, need to make sure instructions are
performed in appropriate order
• “transaction” = 1 single logical function performed by a
thread
– In this case, involving shared memory
– We want it to run atomically
• As we perform individual instructions, things might go
smoothly or not
– If all ok, then commit
– If not, abort and “roll back” to earlier state of computation
• This is easier if we have fewer instructions in a row to do
Keeping the order
Transaction 1 Transaction 2 Transaction 1 Transaction 2
Read (A) Read (A)
Write (A) Write (A)
Read (B) Read (A)
Write (B) Write (A)
Read (A) Read (B)
Write (A) Write (B)
Read (B) Read (B)
Write (B) Write (B)