Sep 05, 2024

Semaphores

I wish I knew what they are and what they do.

Producer-Consumer Problem

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>

#define BUFFER_SIZE 5

int buffer[BUFFER_SIZE];
int in = 0;
int out = 0;

sem_t empty;
sem_t full;

pthread_mutex_t mutex;

void* producer(void* arg) {
    int item;
    while (1) {
        item = rand() % 100;
        sem_wait(&empty);
        pthread_mutex_lock(&mutex);

        buffer[in] = item;
        printf("Producer produced: %d\n", item);
        in = (in + 1) % BUFFER_SIZE;

        pthread_mutex_unlock(&mutex);
        sem_post(&full);

        sleep(1);
    }
}

void* consumer(void* arg) {
    int item;
    while (1) {
        sem_wait(&full);
        pthread_mutex_lock(&mutex);

        item = buffer[out];
        printf("Consumer consumed: %d\n", item);
        out = (out + 1) % BUFFER_SIZE;

        pthread_mutex_unlock(&mutex);
        sem_post(&empty);

        sleep(1);
    }
}

int main() {
    pthread_t prod, cons;

    sem_init(&empty, 0, BUFFER_SIZE);
    sem_init(&full, 0, 0);
    pthread_mutex_init(&mutex, NULL);

    pthread_create(&prod, NULL, producer, NULL);
    pthread_create(&cons, NULL, consumer, NULL);

    pthread_join(prod, NULL);
    pthread_join(cons, NULL);

    sem_destroy(&empty);
    sem_destroy(&full);
    pthread_mutex_destroy(&mutex);

    return 0;
}
Producer produced: 41
Consumer consumed: 41
Producer produced: 67
Consumer consumed: 67
Producer produced: 34
Consumer consumed: 34
Producer produced: 0
Consumer consumed: 0
Producer produced: 69
Consumer consumed: 69
Producer produced: 24
Consumer consumed: 24

Readers-Writers Problem

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>

int read_count = 0;
sem_t mutex;
sem_t write_lock;

void* reader(void* arg) {
    int num = *(int*)arg;
    while (1) {
        sem_wait(&mutex);
        read_count++;
        if (read_count == 1) {
            sem_wait(&write_lock);
        }
        sem_post(&mutex);

        printf("Reader %d is reading\n", num);
        sleep(1);

        sem_wait(&mutex);
        read_count--;
        if (read_count == 0) {
            sem_post(&write_lock);
        }
        sem_post(&mutex);

        sleep(1);
    }
}

void* writer(void* arg) {
    int num = *(int*)arg;
    while (1) {
        sem_wait(&write_lock);

        printf("Writer %d is writing\n", num);
        sleep(1);

        sem_post(&write_lock);

        sleep(1);
    }
}

int main() {
    pthread_t r1, r2, w1, w2;
    int r_id1 = 1, r_id2 = 2, w_id1 = 1, w_id2 = 2;

    sem_init(&mutex, 0, 1);
    sem_init(&write_lock, 0, 1);

    pthread_create(&r1, NULL, reader, &r_id1);
    pthread_create(&r2, NULL, reader, &r_id2);
    pthread_create(&w1, NULL, writer, &w_id1);
    pthread_create(&w2, NULL, writer, &w_id2);

    pthread_join(r1, NULL);
    pthread_join(r2, NULL);
    pthread_join(w1, NULL);
    pthread_join(w2, NULL);

    sem_destroy(&mutex);
    sem_destroy(&write_lock);

    return 0;
}
Reader 1 is reading
Reader 2 is reading
Writer 1 is writing
Writer 2 is writing
Reader 1 is reading
Reader 2 is reading
Writer 1 is writing
Writer 2 is writing
Reader 2 is reading
Reader 1 is reading

Dining Philosophers’ Problem

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>

#define N 5

sem_t chopsticks[N];

void* philosopher(void* num) {
    int id = *(int*)num;
    while (1) {
        printf("Philosopher %d is thinking\n", id);
        sleep(1);

        printf("Philosopher %d is hungry\n", id);
        sem_wait(&chopsticks[id]);
        sem_wait(&chopsticks[(id + 1) % N]);

        printf("Philosopher %d is eating\n", id);
        sleep(2);

        sem_post(&chopsticks[id]);
        sem_post(&chopsticks[(id + 1) % N]);

        printf("Philosopher %d is done eating\n", id);
        sleep(1);
    }
}

int main() {
    pthread_t philosophers[N];
    int philosopher_ids[N];

    for (int i = 0; i < N; i++) {
        sem_init(&chopsticks[i], 0, 1);
    }

    for (int i = 0; i < N; i++) {
        philosopher_ids[i] = i;
        pthread_create(&philosophers[i], NULL, philosopher, &philosopher_ids[i]);
    }

    for (int i = 0; i < N; i++) {
        pthread_join(philosophers[i], NULL);
    }

    for (int i = 0; i < N; i++) {
        sem_destroy(&chopsticks[i]);
    }

    return 0;
}
Philosopher 0 is thinking
Philosopher 1 is thinking
Philosopher 2 is thinking
Philosopher 2 is hungry
Philosopher 1 is hungry
Philosopher 0 is hungry
Philosopher 2 is eating
Philosopher 1 is eating
Philosopher 2 is done eating
Philosopher 2 is thinking
Philosopher 0 is eating