0% found this document useful (0 votes)
22 views2 pages

01 Synchronization Mutex Semaphore

The lab report details the implementation of synchronization solutions for the Producer-Consumer and Dining Philosophers problems using POSIX mutexes and semaphores. It outlines the objectives, theory, algorithms, and design decisions to avoid race conditions, deadlocks, and starvation. The provided code demonstrates the practical application of these concepts in a C program with sample output.

Uploaded by

roshanavhad2004
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)
22 views2 pages

01 Synchronization Mutex Semaphore

The lab report details the implementation of synchronization solutions for the Producer-Consumer and Dining Philosophers problems using POSIX mutexes and semaphores. It outlines the objectives, theory, algorithms, and design decisions to avoid race conditions, deadlocks, and starvation. The provided code demonstrates the practical application of these concepts in a C program with sample output.

Uploaded by

roshanavhad2004
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

Lab Report: Classical Problems of Synchronization

using Mutex and Semaphore


Date of Completion: 11 September 2025
Objectives: Implement and demonstrate solutions to Producer-Consumer and Dining Philosophers using
POSIX mutexes and semaphores. Demonstrate avoidance of race conditions, deadlock, and starvation.
Theory (expanded): In concurrent systems multiple threads access shared data. Without coordination,
race conditions occur where outcome depends on timing. Synchronization primitives: mutex (binary lock),
semaphore (counting/binary), condition variables. Strategies to avoid deadlock: ordering resources, using
an odd-even pick strategy for dining philosophers, using try-lock and back-off, or resource hierarchy.
Starvation can be avoided by fair locking or using semaphores that ensure FIFO ordering.
Algorithms & Design Decisions:
Producer-Consumer (bounded buffer): Use a circular buffer, a mutex to protect buffer, 'empty' semaphore
initialized to buffer_size and 'full' initialized to 0. Producers wait(empty), lock mutex, insert, unlock,
post(full). Consumers wait(full), lock, remove, unlock, post(empty).
Flowchart (Producer):
[Start] -> Produce Item -> wait(empty) -> lock(mutex) -> Insert into buffer -> unlock(mutex) -> post(full) ->
Repeat
Dining Philosophers (avoid deadlock): Use an array of mutexes for forks and a semaphore limiting
maximum philosophers who may try to pick forks (e.g., N-1) to prevent cyclical wait.
Program (synchronization.c)
/* synchronization.c
Producer-Consumer and Dining Philosophers examples using pthreads, mutex and semaphores.
Compile: gcc -o synchronization synchronization.c -lpthread -lrt
*/
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>

/* -------- Producer-Consumer (bounded buffer) -------- */


#define BSIZE 5
int buffer[BSIZE];
int in = 0, out = 0;
pthread_mutex_t mutex;
sem_t empty, full;

void *producer(void *arg) {


int id = *(int*)arg;
for (int i=0;i<10;i++) {
int item = id*100 + i;
sem_wait(&empty);
pthread_mutex_lock(&mutex);
buffer[in] = item;
in = (in+1) % BSIZE;
printf("P%d produced %d\\n", id, item);
pthread_mutex_unlock(&mutex);
sem_post(&full);
usleep(100000);
}
return NULL;
}

void *consumer(void *arg) {


int id = *(int*)arg;
for (int i=0;i<10;i++) {
sem_wait(&full);
pthread_mutex_lock(&mutex);
int item = buffer[out];
out = (out+1) % BSIZE;
printf("C%d consumed %d\\n", id, item);
pthread_mutex_unlock(&mutex);
sem_post(&empty);
usleep(150000);
}
return NULL;
}

/* -------- Dining Philosophers (avoid deadlock by allowing max N-1 eaters) -------- */
#define NPHIL 5
pthread_mutex_t forks[NPHIL];
sem_t room; // allows up to N-1 philosophers into room

void *philosopher(void *arg) {


int id = *(int*)arg;
int left = id;
int right = (id+1) % NPHIL;
for (int i=0;i<5;i++) {
// thinking
printf("Philosopher %d thinking\\n", id);
usleep(100000 + (rand()%200000));
// enter room (prevent deadlock)
sem_wait(&room);
// pick forks (lock smaller id first to avoid deadlock further)
if (left < right) { pthread_mutex_lock(&forks[left]); pthread_mutex_lock(&forks[right]); }
else { pthread_mutex_lock(&forks[right]); pthread_mutex_lock(&forks[left]); }
printf("Philosopher %d eating\\n", id);
usleep(200000);
pthread_mutex_unlock(&forks[left]);
pthread_mutex_unlock(&forks[right]);
sem_post(&room);
}
return NULL;
}

int main() {
/* Producer-consumer demo */
pthread_t p1,p2,c1,c2;
int id1=1,id2=2;
pthread_mutex_init(&mutex,NULL);
sem_init(&empty,0,BSIZE);
sem_init(&full,0,0);
pthread_create(&p1,NULL,producer,&id1);
pthread_create(&p2,NULL,producer,&id2);
pthread_create(&c1,NULL,consumer,&id1);
pthread_create(&c2,NULL,consumer,&id2);
pthread_join(p1,NULL); pthread_join(p2,NULL); pthread_join(c1,NULL); pthread_join(c2,NULL);
pthread_mutex_destroy(&mutex); sem_destroy(&empty); sem_destroy(&full);

/* Dining philosophers demo */


pthread_t ph[NPHIL];
int ids[NPHIL];
sem_init(&room,0,NPHIL-1);
for (int i=0;i<NPHIL;i++) { pthread_mutex_init(&forks[i],NULL); ids[i]=i; }
for (int i=0;i<NPHIL;i++) pthread_create(&ph[i],NULL,philosopher,&ids[i]);
for (int i=0;i<NPHIL;i++) pthread_join(ph[i],NULL);
for (int i=0;i<NPHIL;i++) pthread_mutex_destroy(&forks[i]);
sem_destroy(&room);
return 0;
}

Sample Output (truncated):


P1 produced 100
P2 produced 200
C1 consumed 100
P1 produced 101
...
Philosopher 0 thinking
Philosopher 0 eating
...

You might also like