Problem ucztujących filozofów

Rozwiązanie z kelnerem / arbitrem

Użycie

Przejdź do folderu z kodem źródłowym, następnie:

make
./dining-philosophers-waiter [-d]

Parametr -d - debug pozwala wypisywać szczegółowe informacje o przebiegu algorytmu.

Przykładowy wynik, bez parametru -d (częściowy):

./dining-philosophers-waiter

Dining-philosophers problem. Solution with waiter
    NO_PHILO=5, DEBUG=0

Philosopher id: 0, TID=139930960656128 is eating now
Philosopher id: 1, TID=139930952263424 is eating now
Philosopher id: 4, TID=139930927085312 is eating now
Philosopher id: 2, TID=139930943870720 is eating now
Philosopher id: 0, TID=139930960656128 is eating now
Philosopher id: 3, TID=139930935478016 is eating now
Philosopher id: 1, TID=139930952263424 is eating now
Philosopher id: 2, TID=139930943870720 is eating now
Philosopher id: 4, TID=139930927085312 is eating now
Philosopher id: 0, TID=139930960656128 is eating now
Philosopher id: 3, TID=139930935478016 is eating now

Kod źródłowy

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <pthread.h>
#include <memory.h>
#include <stdbool.h>
#include <semaphore.h>
#include <unistd.h>
#include <stdint.h>
#include "error.h"

#define NO_PHILOSOPHERS 5
bool DEBUG;

sem_t WAITER;
sem_t CHOPSTICKS[NO_PHILOSOPHERS];

int leftChopstick(int i) {
    return i;
}

int rightChopstick(int i) {
    return (i + 1) % 5;
}

void *philosopherJob(void *arg) {
    int id = (int) (uintptr_t) arg;
    while (1) {
        usleep(500000);
        // Check if waiter allows you to join the table
        sem_wait(&WAITER);
        if(DEBUG) printf("  [D] Philosopher id: %i, TID=%ld joined the table\n", id, (long) pthread_self());
        // Acquire chopsticks
        sem_wait(&CHOPSTICKS[rightChopstick(id)]);
        sem_wait(&CHOPSTICKS[leftChopstick(id)]);
        if(DEBUG) printf("  [D] Philosopher id: %i, TID=%ld acquired chopsticks\n", id, (long) pthread_self());

        // Eat
        printf("Philosopher id: %i, TID=%ld is eating now\n", id, (long) pthread_self());
        usleep(500000);

        // Release chopsticks
        sem_post(&CHOPSTICKS[leftChopstick(id)]);
        sem_post(&CHOPSTICKS[rightChopstick(id)]);
        if(DEBUG) printf("  [D] Philosopher id: %i, TID=%ld released chopsticks\n", id, (long) pthread_self());
        sem_post(&WAITER);
        if(DEBUG) printf("  [D] Philosopher id: %i, TID=%ld left the table\n", id, (long) pthread_self());
    }
    return 0;
}

void parseArguments(int argc, char *argv[], int minNumberOfArguments,
                    bool *debug) {
    if (argc < minNumberOfArguments + 1) {
        throwError(
                "Not enough arguments. Usage: ./main [-d]");
    }
    int currentArgument = 1;
    if (argc == minNumberOfArguments + 2 && strcmp(argv[currentArgument++], "-d") == 0) {
        (*debug) = true;
    }
}

int main(int argc, char *argv[]) {
    parseArguments(argc, argv, 0, &DEBUG);
    printf("Dining-philosophers problem. Solution with waiter\n");
    printf("    NO_PHILO=%i, DEBUG=%i\n\n", NO_PHILOSOPHERS, DEBUG);

    // Initialize semaphores
    if (sem_init(&WAITER, 0, 4)) throwError("sem_init error"); // Waiter allows max 4 philosophers
    for (int i = 0; i < NO_PHILOSOPHERS; ++i) {
        if (sem_init(&CHOPSTICKS[i], 0, 1)) throwError("sem_init error");
    }

    // Initialize arrays of threads IDs
    pthread_t *philosophersThreadsIds = malloc(NO_PHILOSOPHERS * sizeof(pthread_t));
    if (philosophersThreadsIds == NULL) { cannotAllocateMemoryError(); }

    // Create philosophers threads
    for (int i = 0; i < NO_PHILOSOPHERS; ++i) {
        if (pthread_create(&philosophersThreadsIds[i], NULL, philosopherJob, (void *) (uintptr_t) i) != 0) {
            throwError("pthread_create error");
        }
    }

    // Wait for philosophers to finish
    for (int i = 0; i < NO_PHILOSOPHERS; ++i) {
        if (pthread_join(philosophersThreadsIds[i], NULL) != 0) {
            throwError("pthread_join error");
        }
    }

    free(philosophersThreadsIds);
    sem_destroy(&WAITER);
    for (int i = 0; i < NO_PHILOSOPHERS; ++i) {
        sem_destroy(&CHOPSTICKS[i]);
    }

    return 0;
}