Ошибка сегментации на Обеденных Философах в C с Pthreads - PullRequest
0 голосов
/ 30 апреля 2020

У меня есть эта проблема ошибки сегментации в упражнении столовых философов с одной нитью на философа, с которой я не могу справиться. Каждый поток думает в течение случайного периода времени и то же самое с едой. Каждый философ может есть двумя вилками, он должен выбрать обе вилки. Чтобы избежать тупика, я сделал сортировку для вил. Философы с нечетным номером сначала выбирают правильную вилку. Я использовал глобальный семафор, который инициализировал функцией init в начале main. Есть кто-то, кто может мне помочь, пожалуйста? Я попытался поставить некоторые fprintf (stderr, "ЗДЕСЬ \ n"), но из-за параллелизма я не могу найти проблему. Вот код

'' '

//global array of semaphore
 pthread_mutex_t *mtx;

//intialize array of semaphore
void init(pthread_mutex_t *mtx){
    mtx=malloc(N*sizeof(pthread_mutex_t));
    if(!mtx){
      perror("malloc fallita\n");
      exit(EXIT_FAILURE);
   }
   for(int i=0;i<N;i++){
     if(pthread_mutex_init(&mtx[i],NULL) != 0){
         perror("init fallita\n");
         exit(EXIT_FAILURE);
     }
   }
 } 



void eat(unsigned int *seed){
  long r = rand_r(seed) % 800000;
  struct timespec t={0,r};
  nanosleep(&t,NULL);
}

void think(unsigned int *seed){
long r = rand_r(seed) % 1000000;
struct timespec t={0,r};
nanosleep(&t,NULL);
}


void *filosofo(void *arg){
    unsigned int id = *((unsigned int*)arg);
    unsigned int seed=id;
    int left = id % N;
    int right = id-1;
    while(1){
        think(&seed);
        if(id % 2){ //il filosofo di indice dispari prende prima la forchetta di destra
            pthread_mutex_lock(&mtx[right]);
            pthread_mutex_lock(&mtx[left]);
            eat(&seed);
            pthread_mutex_unlock(&mtx[left]);
            pthread_mutex_unlock(&mtx[right]);
        }else{ //il filosofo di indice pari prende prima la forchetta a sinista
            pthread_mutex_lock(&mtx[left]);
            pthread_mutex_lock(&mtx[right]);
            eat(&seed);
            pthread_mutex_unlock(&mtx[right]);
            pthread_mutex_unlock(&mtx[left]);
        }
    }

    pthread_exit(NULL);
}



int main(void){
    init(mtx);
    //array of N philosophers
    pthread_t *th;
    th = malloc(N*sizeof(pthread_t));
    if(!th){
        perror("Malloc fallita\n");
        exit(EXIT_FAILURE);
    }
    for(unsigned int i=0;i<N;i++){
        if(pthread_create(&th[i],NULL,filosofo,(void*)(intptr_t)i) != 0){
            perror("create fallita\n");
            exit(EXIT_FAILURE);
        }
    }

    for(unsigned int i=0;i<N;i++){
        if(pthread_join(th[i],NULL) == -1){
            perror("join fallita\n");
        }
    }

    free(th);
    free(mtx);

    return 0;

}

' ''

1 Ответ

0 голосов
/ 30 апреля 2020

Вам нужно заставить init взять указатель на указатель на мьютекс для инициализации. В настоящее время глобальный mtx не изменился.

Вот примерно как:

void init(pthread_mutex_t **mtx){ // pointer to pointer
    *mtx=malloc(N*sizeof(pthread_mutex_t)); // dereference
    if(!*mtx){
      perror("malloc fallita\n");
      exit(EXIT_FAILURE);
   }
   for(int i=0;i<N;i++){
     if(pthread_mutex_init(&(*mtx)[i],NULL) != 0){ // pointer acrobatics
         perror("init fallita\n");
         exit(EXIT_FAILURE);
     }
   }
 }

и затем передайте указатель на глобальный mtx в main:

int main(void){
    init(&mtx);

Я предлагаю по-разному называть ваш глобальный мьютекс и ваш локальный мьютекс в init, чтобы это вас больше не смущало.

Кроме того, прямо здесь вы передаете значение i как void * вместо передачи его адреса:

        if(pthread_create(&th[i],NULL,filosofo,(void*)(intptr_t)i) != 0){

Если вы сделаете это (что я действительно рекомендую избегать условий гонки), то вам следует изменить filosofo, чтобы принимать данные таким же образом :

unsigned int id = (unsigned int)arg;
...