Syncronization
Syncronization
JUNE 2024
SRI RAMAKRISHNA COLLEGE OF ARTS & SCIENCE
1
Classical Synchronization problems: case study Rachna J
2
Classical Synchronization problems: case study Rachna J
Synchronization Problems
The following synchronization problems are considered classical and are often used
to test new synchronization schemes:
2. Dining-Philosophers Problem
3
Classical Synchronization problems: case study Rachna J
Producer: Generates data, places it into the buffer, and then repeats the process.
Consumer: Consumes the data from the buffer, one piece at a time.
Problem: Ensure that the producer does not add data to a full buffer and that the consumer
does not remove data from an empty buffer.
Solution: The producer either goes to sleep or discards data if the buffer is full. When the
consumer removes an item from the buffer, it notifies the producer to start filling the buffer
again. Similarly, the consumer can sleep if the buffer is empty. When the producer adds data to
the buffer, it wakes up the sleeping consumer. An inadequate solution may lead to a deadlock
where both processes wait to be awakened.
- `PC`: The driver class that creates the single `Q`, `Producer`, and `Consumer`.
import java.util.concurrent.Semaphore;
class Q {
// An item
int item;
4
Classical Synchronization problems: case study Rachna J
5
Classical Synchronization problems: case study Rachna J
// Consumer class
class Consumer implements Runnable {
Q q;
Consumer(Q q) {
this.q = q;
new Thread(this, "Consumer").start();
}
6
Classical Synchronization problems: case study Rachna J
}
}
}
// Driver class
class PC {
public static void main(String args[]) {
// Creating buffer queue
Q q = new Q();
Output:
7
Classical Synchronization problems: case study Rachna J
Explanation:
The calls to `put()` and `get()` are synchronized, ensuring that each call to `put()` is
followed by a call to `get()` with no items missed. Without semaphores, multiple calls to `put()`
could occur without matching `get()` calls, resulting in missed items. The sequencing of `put()`
and `get()` calls is managed by two semaphores: `semProd` and `semCon`.
- Before `put()` can produce an item, it must acquire a permit from `semProd`. After producing
the item, it releases `semCon`.
- Before `get()` can consume an item, it must acquire a permit from `semCon`. After consuming
the item, it releases `semProd`.
This “give and take” mechanism ensures that each `put()` call is followed by a `get()` call.
Additionally, `semCon` is initialized with no available permits, ensuring that `put()` executes
first. The ability to set the initial synchronization state is one of the more powerful aspects of
a semaphore.
2. Dining-Philosophers Problem
8
Classical Synchronization problems: case study Rachna J
In this solution, semaphores are used to control access to the chopsticks, preventing
deadlock and ensuring that no two adjacent philosophers eat simultaneously.
Pseudocode:
process P[i]
while true do
{ THINK;
EAT;
9
Classical Synchronization problems: case study Rachna J
Philosophers have three states: THINKING, HUNGRY, and EATING. Two semaphores are
used: `mutex` to ensure mutual exclusion and an array of semaphores for the philosophers to
control their behavior.
Solution in C++:
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#define N 5
#define THINKING 2
#define HUNGRY 1
#define EATING 0
#define LEFT (phnum + 4) % N
#define RIGHT (phnum + 1) % N
int state[N];
int phil[N] = { 0, 1, 2, 3, 4 };
std::mutex mutex;
std::condition_variable S[N];
10
Classical Synchronization problems: case study Rachna J
int main() {
std::thread threads[N];
for (int i = 0; i < N; i++) {
threads[i] = std::thread(philosopher, i);
std::cout << "Philosopher " << i + 1 << " is thinking" << std::endl;
}
11
Classical Synchronization problems: case study Rachna J
Output:
Philosopher 1 is thinking
Philosopher 2 is thinking
Philosopher 3 is thinking
Philosopher 4 is thinking
Philosopher 5 is thinking
Philosopher 1 is Hungry
Philosopher 1 takes fork 5 and 1
Philosopher 1 is Eating
Philosopher 2 is Hungry
Philosopher 3 is Hungry
Philosopher 4 is Hungry
Philosopher 5 is Hungry
Philosopher 1 putting fork 5 and 1 down
Philosopher 1 is thinking
Philosopher 2 takes fork 1 and 2
Philosopher 2 is Eating
Philosopher 3 takes fork 2 and 3
Philosopher 3 is Eating
Philosopher 2 putting fork 1 and 2 down
Philosopher 2 is thinking
Philosopher 3 putting fork 2 and 3 down
Philosopher 3 is thinking
12
Classical Synchronization problems: case study Rachna J
Solution in Python:
import threading
import time
import random
mutex.acquire()
left_fork_index = index
right_fork_index = (index + 1) % num_forks
forks[left_fork_index].acquire()
forks[right_fork_index].acquire()
mutex.release()
13
Classical Synchronization problems: case study Rachna J
forks[left_fork_index].release()
forks[right_fork_index].release()
Output:
Philosopher 0 is thinking...
Philosopher 1 is thinking...
Philosopher 2 is thinking...
Philosopher 3 is thinking...
Philosopher 4 is thinking...
Philosopher 1 is eating...
Philosopher 2 is eating...
Philosopher 0 is eating...
Philosopher 4 is eating...
Philosopher 3 is eating...
Philosopher 1 is thinking...
Philosopher 2 is thinking...
Philosopher 3 is thinking...
Philosopher 4 is thinking...
Philosopher 0 is thinking...
14
Classical Synchronization problems: case study Rachna J
Philosopher 3 is eating...
Philosopher 4 is eating...
Philosopher 0 is eating...
Philosopher 1 is eating...
Philosopher 2 is eating...
Philosopher 0 is thinking...
Philosopher 1 is thinking...
Philosopher 2 is thinking...
Philosopher 3 is thinking...
Philosopher 4 is thinking...
Conclusion
By using semaphores to control access to the forks, the Dining Philosopher Problem
is solved, ensuring that philosophers can eat without deadlock or starvation. The `mutex`
semaphore ensures mutual exclusion while philosophers attempt to pick up forks, and the fork
semaphores ensure that a philosopher can only eat if both adjacent forks are available.
In the Readers and Writers Problem, a database is shared among several concurrent
processes. Some processes only read the database (readers), while others read and write
(writers). Key constraints include:
15
Classical Synchronization problems: case study Rachna J
2. If a reader is reading, other readers may also read, but no writer can write.
Problem Parameters:
In this solution, readers are given preference over writers. This means that if readers are already
reading, a writer must wait until all readers have finished.
16
Classical Synchronization problems: case study Rachna J
- `semaphore mutex`: Ensures mutual exclusion when updating the reader count (`readcnt`).
- `semaphore wrt`: Ensures mutual exclusion for writers and prevents writers when there are
readers.
- `int readcnt`: Counts the number of readers currently in the critical section. Initially set to 0.
Semaphore Functions:
Writer Process:
The writer requests access to the critical section. If allowed (`wait(wrt)` succeeds),
it performs the write and then exits.
do {
// Perform writing
} while (true);
Reader Process:
The reader requests access to the critical section. If allowed, it increments the reader
count. If this is the first reader, it locks the `wrt` semaphore to prevent writers from entering.
After reading, it decrements the reader count and releases the `wrt` semaphore if there are no
more readers.
17
Classical Synchronization problems: case study Rachna J
do {
wait(mutex); // Request access to update readcnt
readcnt++; // Increment reader count
if (readcnt == 1)
wait(wrt); // First reader locks writers
signal(mutex); // Allow other readers to enter
// Perform reading
} while (true);
Complete Implementation:
Reader Process:
int rc = 0;
semaphore mutex = 1;
semaphore db = 1;
void Reader(void) {
while (true) {
down(mutex);
rc = rc + 1;
if (rc == 1)
down(db); // First reader locks writers
up(mutex);
// Reading section
down(mutex);
18
Classical Synchronization problems: case study Rachna J
rc = rc - 1;
if (rc == 0)
up(db); // Last reader releases writers
up(mutex);
// Process data
}
}
Writer Process:
void Writer(void) {
while (true) {
down(db); // Request critical section
// Writing section
up(db); // Release critical section
}
}
Explanation:
1. Reader Process:
2. Writer Process:
- Once allowed, a writer performs its write and then releases `wrt`.
19
Classical Synchronization problems: case study Rachna J
This solution ensures that readers are prioritized, allowing multiple readers to access
the shared resource simultaneously, while writers must wait until there are no readers. This
prevents writers from being starved indefinitely, as they will eventually get access when there
are no readers.
The Sleeping Barber Problem involves a barbershop with one barber, one barber
chair, and N waiting chairs. When there are no customers, the barber sleeps in the barber chair
and must be awakened when a customer arrives. While the barber is cutting hair, new customers
either take an empty seat to wait or leave if no seats are available.
These classical problems highlight the challenges and solutions in managing concurrent
processes and resources effectively.
20
Classical Synchronization problems: case study Rachna J
Problem Description:
- One barber
2. Behavior:
- Customers arrive randomly. If a chair is available, they wait; if not, they leave.
- The barber checks for waiting customers after finishing a haircut. If there are, he cuts the
next customer’s hair; if not, he goes back to sleep.
- `Mutex seats`: Ensures mutual exclusion when accessing the number of available seats.
Implementation in Pseudocode:
Barber {
while (true) {
21
Classical Synchronization problems: case study Rachna J
if (freeSeats > 0) {
// Sitting down
freeSeats--;
22
Classical Synchronization problems: case study Rachna J
up(seats);
// Customer leaves
}
}
}
Python Implementation:
import threading
import time
import random
23
Classical Synchronization problems: case study Rachna J
24
Classical Synchronization problems: case study Rachna J
else:
print(f"Customer {index} is leaving because the waiting room is full")
mutex.release()
Explanation:
1. Barber Process:
- Cuts the customer’s hair and goes back to sleep if no customers are waiting.
25
Classical Synchronization problems: case study Rachna J
2. Customer Process:
- Arrives randomly.
This solution ensures efficient resource use, prevents race conditions, and guarantees
fairness. Proper semaphore use prevents deadlocks and ensures mutual exclusion.
Conclusion
In this case study, we have examined several classical synchronization problems and
their solutions using semaphores. These problems—the Bounded-Buffer (or Producer-
Consumer), Dining-Philosophers, Readers and Writers, and the Sleeping Barber—serve as
fundamental examples to illustrate the challenges and intricacies of process synchronization in
concurrent computing environments.
26
Classical Synchronization problems: case study Rachna J
Semaphores and mutex locks are synchronization primitives that control access to shared
resources among several processes or threads. They ensure that several processes or threads
can access shared resources in a regulated and orderly manner, thereby avoiding conflicts and
maintaining data integrity.
2. Can the solutions to these synchronization issues be addressed with mutex locks
rather than semaphores?
Yes, solutions to these synchronization issues can be achieved utilizing semaphores or mutex
locks. Both semaphores and mutex locks can do comparable synchronization tasks. The
decision between them is often determined by the problem's specific requirements as well as
the programming language or framework in use.
27