分析:
為了避免死鎖,做了如下規定:每個哲學家先拿自己左手邊的筷子,然后再去拿右手邊的筷子,如果不能同時得到兩支筷子,則該哲學家放下手中已有的筷子。這種規定依然會因為振蕩而產生死鎖,例如:每個哲學家都同時拿上了左手邊的筷子,然后都阻塞,都釋放左手筷子;然后又同時去拿左手邊的筷子,這樣周而復始,一直進行下去,就是因為振蕩而產生的死鎖。解決方法:規定其中一位哲學家先拿右手邊的筷子,再拿左手邊的筷子即可。這樣即使最壞的情況下,也至少有一位哲學家可以拿到兩支筷子,而只要有一位哲學家拿到了兩支筷子,就肯定不會出現死鎖。
在這里筷子是臨界資源,即只能被哲學家互斥訪問,因此可以將筷子作為互斥量或者信號量。五支筷子應該引入五個互斥量,或者5個信號量(初始值為1)。將五個哲學家當成五個線程,其編號為i(0、1、2、3、4),互斥量或信號量編號也為0、1、2、3、4。則按照規定:i=0~3時,先拿i,再拿i+1;i=4時,先拿0,再拿i。在此基礎上,對于每一個線程,如果不能同時拿上兩支筷子,則放棄已獲得的筷子,則:第一次用lock函數,采用阻塞加鎖;第二次拿筷子用trylock函數,采用非阻塞加鎖,并且釋放掉已經拿掉的筷子。
注意:互斥量、信號量既可以用于進程間同步,也可以用于線程間同步(一般來說,進程間同步信號量用的多一點);條件變量需要結合互斥量使用;讀寫鎖用于線程間同步,而文件鎖用于進程間同步。
下面線程版采用互斥量,進程版采用信號量
//線程版哲學家用餐模型
#include <pthread.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>pthread_mutex_t mutex[5];void *tfn( void *arg )
{int i = (int)arg;int ret;while(1) {if( i<4 ){pthread_mutex_lock( &mutex[i] );ret = pthread_mutex_trylock( &mutex[i+1] );if( ret != 0){//printf("The %dth philosopher missed the second chopstick!\n", i+1);pthread_mutex_unlock( &mutex[i] );}else{printf("Very good, the %dth philosopher has a pair of chopsticks to eat food!\n", i+1);sleep(5);pthread_mutex_unlock( &mutex[i] );pthread_mutex_unlock( &mutex[i+1] );//break;}}else{pthread_mutex_lock( &mutex[0] );ret = pthread_mutex_trylock( &mutex[i] );if( ret != 0){//printf("The %dth philosopher missed the second chopstick!\n", i+1);pthread_mutex_unlock( &mutex[0] );}else{printf("Very good, the %dth philosopher has a pair of chopsticks to eat food!\n", i+1);sleep(5);pthread_mutex_unlock( &mutex[i] );pthread_mutex_unlock( &mutex[0] );//break;}}}return NULL;
}int main( void )
{int i, ret;pthread_t phi[5];pthread_attr_t attr;ret = pthread_attr_init( &attr );if( ret != 0 ){fprintf(stderr,"pthread_attr_init error: %s.\n", strerror(ret));exit(1);}ret = pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_DETACHED );if( ret != 0 ){fprintf(stderr,"pthread_attr_detach error: %s.\n", strerror(ret));exit(1);}for( i=0; i<5; i++){ret = pthread_mutex_init( &mutex[i], NULL );if( ret != 0 ){fprintf(stderr,"pthread_mutex_init error: %s.\n", strerror(ret));exit(1);}}for( i=0; i<5; i++){ret = pthread_create( &phi[i], &attr, tfn, (void *)i );if( ret != 0 ){fprintf(stderr,"pthread_create error: %s.\n", strerror(ret));exit(1);}}pthread_attr_destroy( &attr );pthread_exit( NULL );
}
[root@localhost 02_pthread_sync_test]# ./philosophy_pthrd
Very good, the 2th philosopher has a pair of chopsticks to eat food!
Very good, the 4th philosopher has a pair of chopsticks to eat food!
Very good, the 1th philosopher has a pair of chopsticks to eat food!
Very good, the 3th philosopher has a pair of chopsticks to eat food!
Very good, the 3th philosopher has a pair of chopsticks to eat food!
Very good, the 1th philosopher has a pair of chopsticks to eat food!
Very good, the 1th philosopher has a pair of chopsticks to eat food!
Very good, the 3th philosopher has a pair of chopsticks to eat food!
Very good, the 3th philosopher has a pair of chopsticks to eat food!
Very good, the 1th philosopher has a pair of chopsticks to eat food!
//進程版哲學家用餐模型
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>
#include <semaphore.h>
#include <sys/mman.h>
#include <sys/wait.h>int main(void)
{int i;pid_t pid;sem_t *s;s = mmap(NULL, sizeof(sem_t)*5, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANON, -1, 0);if (s == MAP_FAILED) {perror("fail to mmap");exit(1);}for (i = 0; i < 5; i++)sem_init(&s[i], 0, 1); //信號量初值制定為1,信號量,變成了互斥鎖for (i = 0; i < 5; i++)if ((pid = fork()) == 0)break;if (i < 5) { //子進程int l, r;srand(time(NULL));if (i == 4)l = 0, r = 4;elsel = i, r = i+1;while (1) {sem_wait(&s[l]);if (sem_trywait(&s[r]) == 0) {printf(" %c is eating\n", 'A'+i);sem_post(&s[r]);}sem_post(&s[l]);sleep(rand() % 5);}exit(0);}for (i = 0; i < 5; i++)wait(NULL);for (i = 0; i < 5; i++)sem_destroy(&s[i]);munmap(s, sizeof(sem_t)*5);return 0;
}
?