5
\$\begingroup\$

I wanted to try multithreading out in C, so I did Dining Philosophers using C11 threads with the approach of having one of the philosophers left-handed. Any suggestions?

#include <stdio.h>
#include <threads.h>
#include <stdlib.h>

#define NUM_THREADS 5

struct timespec time1;
mtx_t forks[NUM_THREADS];

typedef struct {
    char *name;
    int left;
    int right;
} Philosopher;

Philosopher *create(char *nam, int lef, int righ) {
    Philosopher *x = malloc(sizeof(Philosopher));
    x->name = nam;
    x->left = lef;
    x->right = righ;
    return x; 
}

int eat(void *data) {
    time1.tv_sec = 1;
    Philosopher *foo = (Philosopher *) data;
    mtx_lock(&forks[foo->left]);   
    mtx_lock(&forks[foo->right]);
    printf("%s is eating\n",  foo->name);
    thrd_sleep(&time1, NULL);
    printf("%s is done eating\n",  foo->name);
    mtx_unlock(&forks[foo->left]);
    mtx_unlock(&forks[foo->right]);
    return 0;
}

int main(void) {
    thrd_t threadId[NUM_THREADS];
    Philosopher *all[NUM_THREADS] = {create("Teral", 0 ,1), 
                    create("Billy", 1, 2), 
                    create("Daniel", 2,3), 
                    create("Philip", 3, 4),
                    create("Bennet", 0, 4)};
    for (int i = 0; i < NUM_THREADS; i++){
        if (mtx_init(&forks[i], mtx_plain) != thrd_success){
            puts("FAILED IN MUTEX INIT!");
            return 0;
        }
    }
    for (int i=0; i < NUM_THREADS; ++i) {
        if (thrd_create(threadId+i, eat, all[i]) != thrd_success) {
            printf("%d-th thread create error\n", i);
            return 0;
        }
    }

    for (int i=0; i < NUM_THREADS; ++i)
        thrd_join(threadId[i], NULL);
    return 0;
}
\$\endgroup\$
  • \$\begingroup\$ eat() does not implement the dinning Philosopher. The whole point is that if the Philosopher can not get both forks he must release all forks and think (ie do work). The point of the exercise is to fully utilize cores and resource if you can not get all the resources the CPU is supposed to do something useful rather than just idle. \$\endgroup\$ – Martin York Dec 31 '15 at 22:51
  • \$\begingroup\$ Also you do not consider the possibility of deadlock. What happens if all the philosophers manage to grab (lock) their left fork. When they all try to grab (lock) the right fork then all the philosophers will go into deadlock waiting for the right fork (as their college is holding it as their left fork). \$\endgroup\$ – Martin York Dec 31 '15 at 23:02
1
\$\begingroup\$

when calling malloc(), always check the returned value to assure the operation was successful

use meaningful variable names. x is not a meaningful name and just makes the code more difficult to understand.

it seems the threads.h header file is not available everywhere.

For portability, suggest changing to the POSIX threads

#include <pthreads.h> 

and using the related functions like:

pthread_create() 
pthread_exit()
pthread_join()
pthread_t
pthread_mutex_lock()
pthread_mutex_unlock()

when a function fails, most likely one or more of the Philosopher entities have already been created via malloc() to avoid a memory leak, those memory allocation pointers need to be passed to free()

When returning out of main, due to an error, return EXIT_FAILURE (or similar value) rather than returning 0 which indicates success.

in main(), the calls to create() need to check the returned value to assure the operation was a success.

the eat() function just zooms through and exits. This is not the (typical) action of the Dining Philosophers problem. Suggest searching stackoverflow.com for implementations of the problem and using the overall logic, with some modification for the 'left handed' diner.

The posted code fails to free() the malloc'd memory at the end of the main() function

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.