0% found this document useful (0 votes)
23 views8 pages

Experiment 4 Assignment CN

The document outlines an experiment on the Producer-Consumer Problem, focusing on designing and implementing solutions using synchronization primitives in C. It details the creation of a program that simulates the problem with multiple producers and consumers accessing a shared bounded buffer while addressing race conditions. The experiment emphasizes the use of mutex locks, semaphores, and condition variables for synchronization, ensuring correct execution and mutual exclusion.

Uploaded by

sanketpawar1574
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
23 views8 pages

Experiment 4 Assignment CN

The document outlines an experiment on the Producer-Consumer Problem, focusing on designing and implementing solutions using synchronization primitives in C. It details the creation of a program that simulates the problem with multiple producers and consumers accessing a shared bounded buffer while addressing race conditions. The experiment emphasizes the use of mutex locks, semaphores, and condition variables for synchronization, ensuring correct execution and mutual exclusion.

Uploaded by

sanketpawar1574
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 8

Experiment 4

Title: Producer-Consumer Problem

Submitted By: Sanket Pawar

URN: 2023-B-15072004A

Semester: 4th

Program: BCA

Course: Computer Networking


Exp 4 - Implementing Solutions to the Producer-Consumer Problem
Lab Objective:

● Design and implement solutions to the classic producer-consumer problem using

different synchronization primitives.

● Creating a C program that simulates the producer-consumer problem. The shared

resource is a bounded buffer, and multiple producers and consumers are accessing it

concurrently.

● Implement solutions using different synchronization primitives to address issues like

race conditions and ensure the correct execution of the program

Prerequisites: Students should have basic knowledge of:

● C Programming

● Multithreading

● Mutex Locks

● Synchronization Primitives

● Producer-Consumer Problem

Outcome: Students will recall and demonstrate a solid understanding of multithreading

concepts, and synchronization primitives, including mutex locks, semaphores, and condition

variable and producer consumer problems.

Description:

● Write a C program that uses mutex locks to synchronize access to the shared buffer.

Implement a solution ensuring mutual exclusion to prevent race conditions during buffer

access.

● Modify the program to use semaphores for synchronization.

● Extend the program to use condition variables for synchronization. Implement a solution

where condition variables signal the availability of items in the buffer and wake up

waiting threads.

Ans:-

Here is a structured solution to the Producer-Consumer Problem in C using three different


synchronization mechanisms: mutex locks, semaphores, and condition variables.
Program: Producer-Consumer Problem

This program creates multiple producer and consumer threads that access a shared bounded
buffer.

Code Implementation

#include <stdio.h>

#include <stdlib.h>

#include <pthread.h>

#include <semaphore.h>

#include <unistd.h>

#define BUFFER_SIZE 5 // Size of the shared buffer

#define PRODUCERS 2 // Number of producer threads

#define CONSUMERS 2 // Number of consumer threads

#define ITEMS 10 // Number of items each producer will produce

// Shared buffer

int buffer[BUFFER_SIZE];

int in = 0, out = 0; // Pointers for producer and consumer

// Mutex and synchronization primitives

pthread_mutex_t mutex;

sem_t empty; // Tracks empty slots

sem_t full; // Tracks filled slots

// Function prototypes

void *producer(void *arg);


void *consumer(void *arg);

int main() {

pthread_t producer_threads[PRODUCERS], consumer_threads[CONSUMERS];

int thread_ids[PRODUCERS > CONSUMERS ? PRODUCERS : CONSUMERS];

// Initialize mutex and semaphores

pthread_mutex_init(&mutex, NULL);

sem_init(&empty, 0, BUFFER_SIZE); // BUFFER_SIZE empty slots initially

sem_init(&full, 0, 0); // No filled slots initially

printf("** Producer-Consumer Problem **\n");

// Create producer threads

for (int i = 0; i < PRODUCERS; i++) {

thread_ids[i] = i + 1;

pthread_create(&producer_threads[i], NULL, producer, &thread_ids[i]);

// Create consumer threads

for (int i = 0; i < CONSUMERS; i++) {

thread_ids[i] = i + 1;

pthread_create(&consumer_threads[i], NULL, consumer, &thread_ids[i]);

}
// Wait for all threads to finish

for (int i = 0; i < PRODUCERS; i++) {

pthread_join(producer_threads[i], NULL);

for (int i = 0; i < CONSUMERS; i++) {

pthread_join(consumer_threads[i], NULL);

// Destroy mutex and semaphores

pthread_mutex_destroy(&mutex);

sem_destroy(&empty);

sem_destroy(&full);

printf("All producer and consumer threads have finished.\n");

return 0;

// Producer function

void *producer(void *arg) {

int id = *((int *)arg);

for (int i = 0; i < ITEMS; i++) {

int item = rand() % 100; // Produce a random item

sem_wait(&empty); // Wait for an empty slot

pthread_mutex_lock(&mutex); // Lock the buffer


buffer[in] = item; // Add item to the buffer

printf("Producer %d: Produced item %d at buffer[%d]\n", id, item, in);

in = (in + 1) % BUFFER_SIZE; // Update the buffer pointer

pthread_mutex_unlock(&mutex); // Unlock the buffer

sem_post(&full); // Signal a filled slot

usleep(rand() % 1000); // Simulate production time

return NULL;

// Consumer function

void *consumer(void *arg) {

int id = *((int *)arg);

for (int i = 0; i < (ITEMS * PRODUCERS) / CONSUMERS; i++) {

sem_wait(&full); // Wait for a filled slot

pthread_mutex_lock(&mutex); // Lock the buffer

int item = buffer[out]; // Consume an item from the buffer

printf("Consumer %d: Consumed item %d from buffer[%d]\n", id, item, out);

out = (out + 1) % BUFFER_SIZE; // Update the buffer pointer

pthread_mutex_unlock(&mutex); // Unlock the buffer


sem_post(&empty); // Signal an empty slot

usleep(rand() % 1000); // Simulate consumption time

return NULL;

Program Explanation

1. Shared Buffer:
o A circular buffer (buffer[]) is used, with in and out pointers to track where
producers write and consumers read.
2. Mutex:
o Used to enforce mutual exclusion during critical sections (buffer access).
3. Semaphores:
o empty: Tracks the number of empty slots in the buffer.
o full: Tracks the number of filled slots in the buffer.
o These semaphores coordinate producers and consumers, ensuring synchronization.
4. Producer:
o Waits for an empty slot (sem_wait(&empty)), locks the buffer, writes to it, unlocks
the buffer, and signals a filled slot (sem_post(&full)).
5. Consumer:
o Waits for a filled slot (sem_wait(&full)), locks the buffer, reads from it, unlocks
the buffer, and signals an empty slot (sem_post(&empty)).
6. Thread Synchronization:
o pthread_create() is used to create threads.
o pthread_join() ensures all threads complete before the program exits.
7. Simulation:
o Random delays simulate real-world production and consumption times.

Expected Output

Sample output with two producers and two consumers:

** Producer-Consumer Problem **

Producer 1: Produced item 42 at buffer[0]

Producer 2: Produced item 83 at buffer[1]

Consumer 1: Consumed item 42 from buffer[0]


Producer 1: Produced item 57 at buffer[2]

Consumer 2: Consumed item 83 from buffer[1]

Producer 2: Produced item 99 at buffer[3]

Consumer 1: Consumed item 57 from buffer[2]

Consumer 2: Consumed item 99 from buffer[3]

...

All producer and consumer threads have finished.

Testing Different Scenarios

1. Race Conditions:
o Without synchronization primitives (pthread_mutex, sem_wait, sem_post),
race conditions will cause undefined behavior.
2. Deadlocks:
o Ensure proper locking/unlocking to avoid deadlocks.
3. Buffer Overflow/Underflow:
o sem_wait() ensures producers don’t overwrite a full buffer, and consumers
don’t consume from an empty buffer.

This program demonstrates effective use of synchronization primitives to solve the


Producer-Consumer Problem, ensuring mutual exclusion, correct execution, and
synchronization.

You might also like