Practical-10
Title : Implementation of Producer- Consumer problem using semaphores
—---------------------------------------------------------------------------------------------------------------
The Producer-Consumer problem is a classic synchronization problem that illustrates the challenges of resource sharing between multiple processes. It involves two main types of processes: producers, which generate data to be stored in a shared buffer, and consumers, which take data from the buffer for further processing. The challenge is to ensure that producers and consumers access the buffer in a synchronized manner to avoid issues such as data corruption, race conditions, and deadlocks.
In this problem, semaphores are used to manage access to the shared buffer, ensuring that producers do not write to a full buffer and consumers do not read from an empty buffer. We'll use three semaphores:
empty: Represents the number of empty slots available in the buffer.
full: Represents the number of filled slots available in the buffer.
mutex: Ensures mutual exclusion while accessing the buffer.
Here's a step-by-step ALGORITHM of the Producer-Consumer problem using semaphores:
Initialization
Define Constants:
BUFFER_SIZE: Size of the shared buffer.
MAX_ITEMS: Number of items to be produced/consumed.
Initialize Buffer and Indices:
buffer: Array of size BUFFER_SIZE to hold items.
in: Integer to track the next index to insert an item (in = 0).
out: Integer to track the next index to remove an item (out = 0).
Initialize Semaphores and Mutex:
empty: Counting semaphore, initialized to BUFFER_SIZE.
full: Counting semaphore, initialized to 0.
mutex: Binary semaphore (mutex), initialized to 1.
Producer Process
Repeat until all items are produced:
Produce an Item:
Generate a new item to be placed in the buffer.
Wait for an Empty Slot:
wait(empty): Decrement the empty semaphore. If no empty slots are available, wait.
Enter Critical Section:
wait(mutex): Acquire the mutex lock to ensure exclusive access to the buffer.
Add Item to Buffer:
buffer[in] = item: Place the produced item at the current in index.
in = (in + 1) % BUFFER_SIZE: Update the in index using modulo operation to wrap around if necessary.
Exit Critical Section:
signal(mutex): Release the mutex lock, allowing other threads to access the buffer.
Signal a Full Slot:
signal(full): Increment the full semaphore to indicate a filled slot is available.
Simulate Production Delay:
Sleep for a random or fixed duration to simulate production time.
Consumer Process
Repeat until all items are consumed:
Wait for a Full Slot:
wait(full): Decrement the full semaphore. If no filled slots are available, wait.
Enter Critical Section:
wait(mutex): Acquire the mutex lock to ensure exclusive access to the buffer.
Remove Item from Buffer:
item = buffer[out]: Retrieve the item at the current out index.
out = (out + 1) % BUFFER_SIZE: Update the out index using modulo operation to wrap around if necessary.
Exit Critical Section:
signal(mutex): Release the mutex lock, allowing other threads to access the buffer.
Signal an Empty Slot:
signal(empty): Increment the empty semaphore to indicate an empty slot is available.
Simulate Consumption Delay:
Sleep for a random or fixed duration to simulate consumption time.
Code :
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
// Define buffer size
#define BUFFER_SIZE 5
// Buffer array and index
int buffer[BUFFER_SIZE];
int in = 0, out = 0;
// Semaphores
sem_t empty; // Counts empty slots in the buffer
sem_t full; // Counts full slots in the buffer
pthread_mutex_t mutex; // Ensures mutual exclusion for buffer access
// Function for producer thread
void* producer(void* arg) {
int item;
for(int i = 0; i < 10; i++) { // Produces 10 items
item = rand() % 100; // Produces a random item
sem_wait(&empty); // Wait for an empty slot
pthread_mutex_lock(&mutex); // Lock the buffer
// Add item to buffer
buffer[in] = item;
printf("Producer produced: %d\n", item);
in = (in + 1) % BUFFER_SIZE; // Move index
pthread_mutex_unlock(&mutex); // Unlock the buffer
sem_post(&full); // Increase the full slot count
sleep(1); // Simulate production time
}
}
// Function for consumer thread
void* consumer(void* arg) {
int item;
for(int i = 0; i < 10; i++) { // Consumes 10 items
sem_wait(&full); // Wait for a full slot
pthread_mutex_lock(&mutex); // Lock the buffer
// Remove item from buffer
item = buffer[out];
printf("Consumer consumed: %d\n", item);
out = (out + 1) % BUFFER_SIZE; // Move index
pthread_mutex_unlock(&mutex); // Unlock the buffer
sem_post(&empty); // Increase the empty slot count
sleep(1); // Simulate consumption time
}
}
int main() {
pthread_t prodThread, consThread;
// Initialize semaphores
sem_init(&empty, 0, BUFFER_SIZE);
sem_init(&full, 0, 0);
pthread_mutex_init(&mutex, NULL);
// Create producer and consumer threads
pthread_create(&prodThread, NULL, producer, NULL);
pthread_create(&consThread, NULL, consumer, NULL);
// Wait for threads to finish
pthread_join(prodThread, NULL);
pthread_join(consThread, NULL);
// Destroy semaphores and mutex
sem_destroy(&empty);
sem_destroy(&full);
pthread_mutex_destroy(&mutex);
return 0;
}
No comments:
Post a Comment