Professional Documents
Culture Documents
Synchronization
Examples
Edited by
Ghada Mohammed S AlOsaimi
CS Lecturer, CCIS, IMSIU
Outline
Bounded-Buffer Problem
Readers-Writers Problem
Dining-Philosophers Problem
Process
Management
Storage
Management
2
Objectives
Explain the bounded-buffer, readers-writers, and dining philosophers
synchronization problems.
3
Classical Problems of Synchronization
In our solutions to the problems above, we use semaphores for synchronization, since that is the traditional way to present
such solutions
However, actual implementations of these solutions could use mutex locks in place of binary semaphores
4
Bounded-Buffer Problem
Sometimes, it is called producer-consumer problem and commonly used to illustrate the power of synchronization primitives
The idea is that a producer tries to insert data into an empty slot of the buffer and a consumer tries to remove data from a
filled slot in the buffer. The problem is occurred when:
Multiple producer threads
Multiple consumer threads
One bounded buffer with N entries
All threads modify the same buffer
5
Bounded-Buffer Problem (cont.)
In order to implement the producer consumer problem correctly, the following constraints should be satisfied:
Consumer must wait for producer to fill the shared buffer, if none in the buffer (scheduling constraint)
Producer must wait for consumer to empty the buffer, if the buffer is full (scheduling constraint)
Only one thread can manipulate the buffer queue at a time (mutual exclusion)
The solution is accomplished by using Semaphore values, in our problem, the producer and consumer processes share the
following data structures:
6 Semaphore full initialized to the value 0 → count the number of full buffers
Semaphore empty initialized to the value n → count the number of empty buffers
Bounded-Buffer Problem - Process Structure
Producer Consumer
while (true) { while (true) {
... /* wait until full > 0 and then decrement full’*/
/* produce an item in next_produced */
wait(full);
wait(mutex); // acquire lock
/* wait until empty > 0 and then decrement 'empty’*/
...
wait(empty); /* remove an item from buffer to next_consumed */
wait(mutex); // acquire lock ...
... signal(mutex); // release lock
/* add next produced to the buffer */
signal(empty); // increment full
...
signal(mutex); // release lock
/* consume the item in next consumed */
signal(full); // increment full
...
} }
7
POSIX Semaphore – Bounded-Buffer Problem
8
Readers-Writers Problem
A data set is shared among a number of concurrent processes, some of these processes may want only to read the data set,
whereas others may want to update (that is, read and write)
Readers – only read the data set; they do not perform any updates
Writers – can both read and write
Obviously, if two readers access the shared data simultaneously, no adverse effects will result
However, if a writer and some other process (either a reader or a writer) access the database simultaneously, chaos may
happen!
To ensure that these difficulties do not arise, we require that the writers have exclusive access to the shared database while
writing to the database or data set
This synchronization problem is referred to as the readers-writers problem
9
Readers-Writers Problem Variations
Several variations of how readers and writers are considered – all involve some form of priorities
First variation – no reader kept waiting unless writer has permission to use shared object, in other words, no reader
should wait for other readers to finish simply because a writer is waiting
Second variation – once writer is ready, it performs the write ASAP, in other words, if a writer is waiting to access the
object, no new readers may start reading
Both may have starvation leading to even more variations
In the first case, writers may starve
In the second case, readers may starve
Problem is solved on some systems by kernel providing reader-writer locks
10
Readers-Writers Problem Variations (cont.)
In this lecture, we will discuss the solution of the first readers-writers problem, and in your textbook you will find more
references on solving the second readers-writers problem. First variation shares following data structures:
Semaphore mutex initialized to 1 → is used to ensure mutual exclusion when the variable read count is updated
Integer read_count initialized to 0 → keeps track of how many processes are currently reading the object
11
Readers-Writers Problem - Process Structure
Reader
while (true){
wait(mutex); //reader acquire lock to update count
read_count++;
if (read_count == 1)
wait(rw_mutex); // to ensure no writers
Writer
signal(mutex); //reader release lock to update count
while (true) {
wait(rw_mutex); //writer acquire lock ...
/* reading is performed */
...
/* writing is performed */ ...
... wait(mutex); //reader acquire lock to update count
read count--;
signal(rw_mutex); //writer release lock if (read_count == 0)
} signal(rw_mutex); // enable no writers
13
Dining-Philosophers Problem
Consider five philosophers who spend their lives thinking and eating
The philosophers share a circular table surrounded by five chairs, each belonging to one philosopher
In the center of the table is a bowl of rice, and the table is laid with five single chopsticks
When a philosopher thinks, she does not interact with her colleagues
From time to time, a philosopher gets hungry and tries to pick up the two chopsticks that are closest to her (the chopsticks
that are between her and her left and right neighbors)
A philosopher may pick up only one chopstick at a time, obviously, she cannot pick up a chopstick that is already in the hand
of a neighbor
When a hungry philosopher has both her chopsticks at the same time, she eats without releasing the chopsticks
When she is finished eating, she puts down both chopsticks and starts thinking again
The dining-philosophers problem is considered a classic synchronization problem, it is a simple representation of the need to
allocate several resources among several processes in a deadlock free and starvation free manner
14
Dining-Philosophers Problem - Semaphore Solution
Shared Data: Bowl of rice - data set + Semaphore chopstick [5] initialized to 1
The structure of process philosopher i:
while (true){
wait (chopstick[i] );
wait (chopStick[ (i + 1) % 5 ] );
signal (chopstick[i] );
signal (chopstick[ (i + 1) % 5 ] );
Although this solution guarantees that no two neighbors are eating simultaneously, it nevertheless must be rejected because
it could create a deadlock
Suppose that all five philosophers become hungry at the same time and each grabs her left chopstick
All the elements of chopstick will now be equal to 0 .
When each philosopher tries to grab her right chopstick, she will be delayed forever
16
Dining-Philosophers Problem - Semaphore Solution (cont.)
Allow a philosopher to pick up her chopsticks only if both chopsticks are available (to do this, she must pick them up in
a critical section)
Use an asymmetric solution that is, an odd numbered philosopher picks up first her left chopstick and then her right
chopstick, whereas an even numbered philosopher picks up her right chopstick and then her left chopstick
17
Monitor
Monitors are a synchronization construct that were created to overcome problems caused by semaphores as timing errors
Monitors are abstract data types and contain shared data variables and procedures
The shared data variables cannot be directly accessed by a process;
and procedures are required to allow a single process to access the shared data variables at a time
Only one process can be active in a monitor at a time
Other processes that need to access the shared variables in a monitor have to line up in a queue and are only provided
access when the previous process release the shared variables
Using monitor to solve the problem will not lead to deadlock
But starvation is possible !
18
Dining-Philosophers Problem - Monitor Solution
To code this solution, we need to distinguish among three states in which we may find a philosopher
enum {THINKING, HUNGRY, EATING} state[5 ]; // shared data
Philosopher i can set the variable state[ i ] = EATING only if her two neighbors are not eating
(state[(i+4) % 5] != EATING) and (state[(i+1) % 5] != EATING
We also need to declare condition self[5];
This allows philosopher i to delay herself when she is hungry but is unable to obtain the chopsticks she needs
Each philosopher, before starting to eat, must invoke the operation pickup()
This act may result in the suspension of the philosopher process, after the successful completion of the operation, the
philosopher may eat
Following this, the philosopher invokes the putdown()operation
Thus , philosopher i must invoke the operations pickup()and putdown() in the following sequence
DiningPhilosophers.pickup(i);
19 /** EAT **/
DiningPhilosophers.putdown(i);
Dining-Philosophers Problem - Monitor Solution (cont.)
monitor DiningPhilosophers
{
void test (int i) {
enum { THINKING; HUNGRY, EATING) state [5] ;
if ((state[(i + 4) % 5] != EATING) &&
condition self [5];
(state[i] == HUNGRY) &&
(state[(i + 1) % 5] != EATING) ) {
void pickup (int i) {
state[i] = HUNGRY;
state[i] = EATING ;
test(i);
self[i].signal () ;
if (state[i] != EATING) self[i].wait;
}
}
}