程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> 利用Linux下的pthread_mutex_t類型來實現哲學家進餐問題,pthreadmutexlock

利用Linux下的pthread_mutex_t類型來實現哲學家進餐問題,pthreadmutexlock

編輯:關於C語言

利用Linux下的pthread_mutex_t類型來實現哲學家進餐問題,pthreadmutexlock


  首先說一下什麼是哲學家進餐問題,這是操作系統課程中一個經典的同步問題,

  

  問題如下:如上圖,有6個哲學家和6根筷子(那個藍色部分表示哲學家,那個紫色長條部分表示筷子),他們分別被編了0~5的號!如果某個哲學家想要進餐的話,必須同時拿起左手和右手邊的兩根筷子才能進餐!哲學家進餐完畢之後,就放下手中拿起的兩根筷子!這樣其他哲學家就能拿這些筷子進餐了!

  OK,這樣就可能存在一個死鎖問題,比如0號哲學家拿了0號筷子,1號哲學家拿了1號筷子!如此往復,最終的結果就是每個哲學家都只拿了1根筷子,每個人都無法進餐,同時也無法放下手中的筷子!這樣就產生了死鎖!

  那麼死鎖該如何解決呢?很簡單,就是根據哲學家的編號!如果是偶數號的哲學家,則先拿右手邊筷子(小的號),再拿左手邊的筷子(大的號)。而奇數號的哲學家則剛好相反!這樣,就不會出現每個哲學家都只拿了一根筷子的情況出現了!

 

  具體程序如何實現呢?代碼如下:

  1 /* 說明,本程序是為了模擬實現哲學家進餐的問題,一共有6個哲學家和6根筷子
  2  */
  3 #include<stdio.h>
  4 #include<string.h>
  5 #include<stdlib.h>
  6 #include<unistd.h>
  7 #include<errno.h>
  8 #include<pthread.h>
  9 
 10 #define B_SIZE 4096
 11 #define NUM_P 6
 12 
 13 typedef struct phi
 14 {
 15    pthread_mutex_t chopsticks[NUM_P];    //五根筷子 
 16    int num;                //哲學家的編號
 17    pthread_mutex_t num_lock;        //哲學家編號的鎖
 18 }Phi,*PPhi;
 19 void * tfunc(void *arg)
 20 {
 21     PPhi sp = (PPhi)arg;
 22     int phi_num;
 23     int next_num;
 24 
 25     /*讀取哲學家的編號*/
 26     phi_num = sp->num;
 27     pthread_mutex_unlock(&sp->num_lock);
 28     printf("No.%d philosopher has comed\n",phi_num);
 29     /*下一根筷子*/
 30     next_num= phi_num+1>=NUM_P?phi_num+1-NUM_P:phi_num+1;
 31 
 32     sleep(5);    //所有線程統一睡眠5S,來等待其他線程創建完成
 33 
 34     if(phi_num%2 == 1)    //奇數號先拿大的,再拿小的
 35     {
 36     pthread_mutex_lock(&(sp->chopsticks[next_num]));
 37     //printf("No.%d philosopher lock the No.%d chopstick\n",phi_num,next_num);
 38     pthread_mutex_lock(&(sp->chopsticks[phi_num]));
 39     //printf("No.%d philosopher lock the No.%d chopstick\n",phi_num,phi_num);
 40 
 41     printf("No.%d philosopher has eated!\n",phi_num);
 42 
 43     pthread_mutex_unlock(&(sp->chopsticks[next_num]));
 44     //printf("No.%d philosopher unlock the No.%d chopstick\n",phi_num,next_num);
 45     pthread_mutex_unlock(&(sp->chopsticks[phi_num]));
 46     //printf("No.%d philosopher unlock the No.%d chopstick\n",phi_num,phi_num);
 47     }
 48     else        //偶數號先拿小的,再拿大的
 49     {
 50     pthread_mutex_lock(&(sp->chopsticks[phi_num]));
 51     //printf("No.%d philosopher lock the No.%d chopstick\n",phi_num,phi_num);
 52     pthread_mutex_lock(&(sp->chopsticks[next_num]));
 53     //printf("No.%d philosopher lock the No.%d chopstick\n",phi_num,next_num);
 54 
 55     printf("No.%d philosopher has eated!\n",phi_num);
 56 
 57     pthread_mutex_unlock(&(sp->chopsticks[phi_num]));
 58     //printf("No.%d philosopher unlock the No.%d chopstick\n",phi_num,phi_num);
 59     pthread_mutex_unlock(&(sp->chopsticks[next_num]));
 60     //printf("No.%d philosopher unlock the No.%d chopstick\n",phi_num,next_num);
 61     }
 62 
 63     return (void*)0;
 64 }
 65 int main(int argc,char *argv[])
 66 {
 67     int err;
 68     pthread_t tid[NUM_P];
 69     char buf_err[B_SIZE];   //用於保存錯誤信息
 70     void *retv;            //子線程的返回值
 71     Phi phis;
 72 
 73     for(int loop=0;loop<NUM_P;loop++)
 74     {
 75     /*設置哲學家的編號*/
 76     pthread_mutex_lock(&phis.num_lock);
 77     phis.num = loop;    
 78 
 79     /*創建子線程當作哲學家*/
 80     err = pthread_create(&tid[loop],NULL,tfunc,&phis);
 81     if(0 != err)
 82     {
 83         memset(buf_err,0,B_SIZE);
 84         sprintf(buf_err,"[create]:%s\n",strerror(err));
 85         fputs(buf_err,stderr);
 86         exit(EXIT_FAILURE);
 87     }
 88     }
 89 
 90     for(int loop=0;loop<NUM_P;loop++)
 91     {
 92     err = pthread_join(tid[loop],&retv);
 93     if(0 != err)
 94     {
 95         memset(buf_err,0,B_SIZE);
 96         sprintf(buf_err,"[join]:%s\n",strerror(err));
 97         fputs(buf_err,stderr);
 98         exit(EXIT_FAILURE);
 99     }
100     
101     printf("Main:thread return the value: %d\n",(int)retv);
102     }
103 
104     return 0;
105 }

  在上面的程序中,我創建了一個結構體PHI!其中,chopsticks是定義的五個互斥鎖,用來表示5根筷子!num變量用來表示哲學家的編號,而那個num_lock表示對哲學家編號進行一個鎖定,這個為什麼要這麼設置,隨後會講到!

  首先講主程序,就是創建NUM_P個子線程用來表示這麼多個哲學家!在子線程裡面,需要根據哲學家編號的奇偶性來選擇不同的拿筷子的方法!這就需要傳一個哲學家編號給這個子線程!通過什麼傳呢,就是PHI結構體中的num變量!這裡我們會碰到一個問題!就是如果在主線程裡面設置了num,隨後就創建了子線程,但是子線程還沒來得及讀出這個num的值,主線程已經開始了下一次的循環,那麼很有可能導致子線程讀到的num值並不是我們想要讓它讀到的!所以這裡就用到了num_lock這個鎖,主線程寫了num的值後,就把num_lock這個鎖給鎖定,然後子線程讀到num的之後,才把num_lock這個鎖給解鎖,然後主線程才能進行下一次循環!這樣就可以確保子線程讀到的編號就是我們想要給他傳的編號!

  在子線程裡面,我首先輸出一句"No.%d philosopher has comed\n",表示某個子線程已經創建好了!然後就讓這個線程睡眠5S,等待其他子線程創建完畢(這個其實不需要的,但是我感覺得讓哲學家們大致是一起開始吃飯的麼。。。^_~)!然後就照著上面那個思路,偶數號的哲學家先拿右手邊筷子,再拿左手邊筷子,奇數號哲學家則正好相反!這樣就能避免死鎖了!

  還有一個問題就是我在子線程裡面定義的這個next_num這個變量,這個用來表示哲學家拿的下一根筷子的值,因為最大編號的那個哲學家的下一根筷子是第0號筷子,所以我這裡用了一個if判斷來分辨!

  最後程序的運行結果如下:

  

  OK,就是這些了!希望能夠對學習操作系統的朋友們產生一些幫助!

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved