jsl039
jsl039

Reputation: 13

C passing array to pthread in Dining Philosopher

I'm writing code for the Dining Philosopher thread problem for N number of philosophers from user input. I get an error for dereferencing void * pointer. What am I doing wrong specifically with passing in the array?

 void *philosopher(void *arg_l);

 int main()
 {   
     int i,A,B;
     scanf("%10d", &A);
     scanf("%10d", &B);
     printf("You got %d phils and %d turns each\n",A,B);

     int args[2];
     args[0] = A;
     args[1] = B;

     pthread_t thread_id[A];
     sem_init(&mutex,0,1);
     for(i=0;i<A;i++)
         sem_init(&S[i],0,0);
     for(i=0;i<A;i++)
     {
         args[2] = phil_num[i];
         pthread_create(&thread_id[i],NULL,philosopher,&args);
         printf("Philosopher %d is thinking\n",i+1);
     }
     for(i=0;i<A;i++)
         pthread_join(thread_id[i],NULL);
}

void *philosopher(void *arg_l)
{
    arg_l[0] = int A;
    arg_l[1] = int B;
    ...
    return NULL;
}

Upvotes: 1

Views: 452

Answers (2)

Jonathan Leffler
Jonathan Leffler

Reputation: 754590

Your lines like:

arg_l[0] = int A;

are completely broken. You would get away with:

int A = ((int *)arg_l)[0];

You cannot dereference a void * validly, nor can you index them (in part because that requires dereferencing, in part because in standard C — as opposed to GNU C — the sizeof(void) is undefined). You need to convert to an appropriate type with a cast and then derefence, as shown.

Note: args[2] = phil_num[i]; is writing out of bounds (you define int args[2]; but it appears you need int args[3];.

You have to pass each philosopher a separate array because there is no guarantee that a given thread will have read the information before the main thread reassigns a new value. Usually, you'll use a structure, not an array, for the data passed to an individual thread; you have an initialized array of those structures so that each thread gets its own unique control information.

Is there any way you can give an example of this?

Somewhat like this. The key point is the array of struct Info, each of which is separately initialized (using a C99 compound literal) and a different element of the array is passed to each thread so that it gets its own data, rather than trying to share data with other threads.

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

#pragma GCC diagnostic ignored "-Wdeprecated-declarations"

struct Info
{
    int number;
    int turns;
    int diner;
};

enum { MAX_PHILOSOPHERS = 10 };
enum { MAX_TURNS = 99 };
static sem_t mutex;
static sem_t S[MAX_PHILOSOPHERS];
static void *philosopher(void *arg_l);

int main(void)
{
    int A, B;
    printf("How many philosophers? How many turns? ");
    fflush(stdout);
    if (scanf("%d %d", &A, &B) != 2)
    {
        fprintf(stderr, "Failed to read input\n");
        return 1;
    }
    if (A < 2)
        fprintf(stderr, "You specified too few philosophers (%d)\n", A);
    if (A > MAX_PHILOSOPHERS)
        fprintf(stderr, "You specified too many philosophers (%d, but the maximum is %d)\n",
                A, MAX_PHILOSOPHERS);
    if (B < 1)
        fprintf(stderr, "You specified too few turns (%d)\n", B);
    if (B > MAX_TURNS)
        fprintf(stderr, "You specified too many turns (%d, but the maximum is %d)\n",
                B, MAX_TURNS);
    if (A < 2 || A > MAX_PHILOSOPHERS || B < 1 || B > MAX_TURNS)
        return 1;
    printf("You have %d philosophers who get %d turns each\n", A, B);

    /* This assignment could be in the thread creation loop before pthread_create() */
    /* Or in the loop that uses sem_init() */
    struct Info info[A];
    for (int i = 0; i < A; i++)
        info[i] = (struct Info){ A, B, i};

    sem_init(&mutex, 0, 1);
    for (int i = 0; i < A; i++)
        sem_init(&S[i], 0, 0);

    pthread_t thread_id[A];
    for (int i = 0; i < A; i++)
    {
        pthread_create(&thread_id[i], NULL, philosopher, &info[i]);
        printf("Philosopher %d is thinking\n", i + 1);
    }

    for (int i = 0; i < A; i++)
        pthread_join(thread_id[i], NULL);

    printf("Dinner is over\n");
    return 0;
}

static void *philosopher(void *arg_l)
{
    struct Info *info = arg_l;
    printf("N = %d, T = %d, I = %d\n", info->number, info->turns, info->diner);
    /* ...do dining stuff; remember to share nicely!... */
    return 0;
}

The #pragma allows the code to compile on macOS Sierra, which doesn't have working versions of the <semaphore.h> functions — they just return an error indication and set errno to ENOSYS (function not implemented). This code should check the return value of the pthread functions and the semaphore operations too — it is being lazy not to do so.

Upvotes: 0

dbush
dbush

Reputation: 224437

Since arg_l has type void *, you can't use the subscript operator [] on it. That would mean each element has type void, which cannot be instantiated. Also, the syntax on the right side of the assignment is not valid.

You need to cast the thread argument to int * before you can use it. Also, you need to pass in args without taking its address, since an array decays into a pointer to the first element when passed to a function.

pthread_create(&thread_id[i],NULL,philospher,args);

...

void *philospher(void *arg_l)
{
     int *args = arg_l;
     ...

}

Upvotes: 1

Related Questions