I am having an issue with the following C code. The code itself is supposed to create 5 threads that simulate the Dining Philosophers problem in which threads are accessing shared data. The code follows:
#include <pthread.h> #include <stdio.h> #include <stdlib.h> //creation of the mutex lock, condition variables, and state pthread_mutex_t mutex; pthread_cond_t cond_var[5]; enum{THINKING, HUNGRY, EATING}state[5]; //test if possible to get forks void test(int pNumber){ //start eating if the adjacent philosophers aren't eating if((state[(pNumber + 1) % 5] != EATING) && (state[(pNumber + 4) % 5] != EATING)){ state[pNumber] = EATING; //signal self if test() called by another thread pthread_cond_signal(&cond_var[pNumber]); } } //used to make the philosopher's forks unavailable void pickup_forks(int pNumber){ //get lock pthread_mutex_lock(&mutex); //set state to hungry state[pNumber] = HUNGRY; printf("Philosopher %d is HUNGRYn", pNumber); //attempt to begin eating. if unable to, will wait test(pNumber); while(state[pNumber] != EATING){ pthread_cond_wait(&cond_var[pNumber], &mutex); //switched the order of the arguments } //release lock pthread_mutex_unlock(&mutex); } //allow neighbors to use philosopher's forks void release_forks(int pNumber){ //get lock pthread_mutex_lock(&mutex); //set own state to thinking state[pNumber] = THINKING; //tell adjacent philosophers to try to eat test(((pNumber + 1) % 5)); test(((pNumber + 4) % 5)); //release lock pthread_mutex_unlock(&mutex); } //used by the thread to run the philosophers void *runPhilosopher(void *x){ //which philosopher it is int pNumber = *((int*) x); //initially thinking state[pNumber] = THINKING; printf("Philosopher %d is THINKINGn", pNumber); //"think" for a random amount of time between 1-3 seconds int sleepTime = rand() % 3 + 1; sleep(sleepTime); //each philosopher eats a total of 5 times int i = 0; for(i = 0; i < 5; i++){ //get the forks and begin eating pickup_forks(pNumber); //eating time sleep(2); //put down forks and resume thinking release_forks(pNumber); sleepTime = rand() % 3 + 1; sleep(sleepTime); } printf("Philosopher %d has finished eatingn", pNumber); } int main(int argc, char *argv[]) { pthread_mutex_init(&mutex, NULL); int i = 0; for(i = 0; i < 5; i++){ pthread_cond_init(&cond_var[i], NULL); } pthread_t tid[5]; //thread id pthread_attr_t attr; //set of thread attributes pthread_create(&tid[0], NULL, runPhilosopher, (void *) 0); pthread_create(&tid[1], NULL, runPhilosopher, (void *) 1); pthread_create(&tid[2], NULL, runPhilosopher, (void *) 2); pthread_create(&tid[3], NULL, runPhilosopher, (void *) 3); pthread_create(&tid[4], NULL, runPhilosopher, (void *) 4); //wait for threads to finish for(i = 0; i < 5; i++){ pthread_join(tid[i], NULL); } return 0; }
I am on a Linux virtual machine, using gedit. The program compiles fine, but upon attempting to run it, I am getting a “Segmentation Fault” error, which is coming from the attempted thread creations, according to gdb. None of the related questions here that I found applied to my program.
Things I have tried:
- Commenting out the vast majority of the code and attempting to create a single thread that simply runs runPhilosopher, which had been stripped to just a single printf statement. This resulted in the code seemingly not creating the thread, as there was no output.
- Replacing NULL in the thread creations with &attr. This changed the error to Aborted, but did nothing else.
- Using a single thread id for all of them, as I have in a previous program. This made no difference.
- A few other odds and ends that I can’t remember
Does anybody see a simple solution that I’ve simply overlooked, or is there a serious flaw in my program? I can’t understand what the issue could be, but I fully admit that I’m hardly well-versed in C. Any help would be greatly appreciated!
Advertisement
Answer
Your problem is here:
int pNumber = *((int*) x);
You cast an integer to a pointer when you call pthread_create()
, but then you cast it to a pointer in the thread function and proceed to dereference it.
Instead, try
int pNumber = (int) x;
Note that this may cause a compiler warning of sizeof(int) != sizeof(void*)
. You may want to cast to uintptr_t
first.
Alternatively, you could store the int
in a local variable and pass the address of this to pthread_create
. Just be sure that all threads have stopped before the containing function returns.
Or, you could malloc
a structure with this int
as a member, and pass a pointer to it.