首页 > 解决方案 > 使用 Pthreads 在 C 中就餐哲学家的分段错误

问题描述

我在用餐哲学家的练习中遇到了这个分段错误问题,每个哲学家一个线程,我无法管理。每个线程思考一个随机的时间段,与吃相同。每个哲学家可以用两把叉子吃饭,他必须把两把叉子都挑起来吃。为了避免僵局,我为采摘叉做了一个排序。奇数的哲学家首先选择正确的叉子。我使用了一个全局信号量,我在 main 开始时使用函数 init 对其进行了初始化。请问有人可以帮助我吗?我试图放一些 fprintf(stderr,"HERE\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;

}

'''

标签: csegmentation-faultpthreads

解决方案


您需要将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);
     }
   }
 }

然后将指针传递给全局mtxin main

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

我建议以不同的方式命名您的全局互斥锁和本地互斥锁,init这样就不会再让您感到困惑了。

另外,在这里,您将 的值i作为 avoid *传递,而不是传递其地址:

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

如果你这样做(我实际上建议避免竞争条件),那么你应该改变filosofo以同样的方式接受输入:

unsigned int id = (unsigned int)arg;

推荐阅读