#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>

#define EXTRA_DELAY_TO_SHOW_DEADLOCK

void check(int error) {
    if (error != 0) {
        fprintf(stderr, "Error: %s\n", strerror(error));
        exit(EXIT_FAILURE);
    }
}

pthread_mutex_t vork[5] = {
    PTHREAD_MUTEX_INITIALIZER,
    PTHREAD_MUTEX_INITIALIZER,
    PTHREAD_MUTEX_INITIALIZER,
    PTHREAD_MUTEX_INITIALIZER,
    PTHREAD_MUTEX_INITIALIZER
};

void* philosopher(void* par) {
    int i = *(int*)par;
    while (1) {
        printf("philosopher %d is sleeping\n", i);
        sleep(1);
        check( pthread_mutex_lock(&vork[i]) );
#ifdef EXTRA_DELAY_TO_SHOW_DEADLOCK
        sleep(1);
#endif
        check( pthread_mutex_lock(&vork[(i + 1) % 5]) );
        printf("philosopher %d is eating\n", i);
        check( pthread_mutex_unlock(&vork[i]) );
        check( pthread_mutex_unlock(&vork[(i + 1) % 5]) );
    }
    return NULL;
}

int main(void) {
    int i;
    pthread_t t[5];

    for (i = 0; i < 5; i++) {
        check( pthread_create(&t[i], NULL, &philosopher, &i) );
    }
    for (i = 0; i < 5; i++) {
        check( pthread_join(t[i], NULL) );
    }

    return EXIT_SUCCESS;
}
