哲学家用餐模型分析

#include 
    
    
     
     
#include 
     
     
      
      
#include 
      
      
       
       
#include 
       
       
        
        

pthread_mutex_t m[5];

void *tfn(void *arg)
{
	int i, l, r;

	srand(time(NULL));
	i = (int)arg;

	if (i == 4)
		l = 0, r = i;
	else
		l = i; r = i+1;

	while (1) {
		pthread_mutex_lock(&m[l]);
		if (pthread_mutex_trylock(&m[r]) == 0) {
			printf("\t%c is eating \n", 'A'+i);
			pthread_mutex_unlock(&m[r]);
		}
		pthread_mutex_unlock(&m[l]);
		sleep(rand() % 5);
	}

	return NULL;
}

int main(void)
{
	int i;
	pthread_t tid[5];
	
	for (i = 0; i < 5; i++)
		pthread_mutex_init(&m[i], NULL);

	for (i = 0; i < 5; i++)
		pthread_create(&tid[i], NULL, tfn, (void *)i);

	for (i = 0; i < 5; i++)
		pthread_join(tid[i], NULL);

	for (i = 0; i < 5; i++)
		pthread_mutex_destroy(&m[i]);

	return 0;
}


       
       
      
      
     
     
    
    
多线程版:

         选用互斥锁mutex,如创建5个, pthread_mutex_t m[5];

         模型抽象:    

                   5个哲学家 --> 5个线程;    5支筷子 --> 5把互斥锁                  int left(左手), right(右手)

                   5个哲学家使用相同的逻辑,可通用一个线程主函数,void *tfn(void *arg),使用参数来表示线程编号:int i = (int)arg;

                   哲学家线程根据编号知道自己是第几个哲学家,而后选定锁,锁住,吃饭。否则哲学家thinking。

                                                                                A  B   C   D   E

                   5支筷子,在逻辑上形成环:0   1  2   3   4   分别对应5个哲学家:


所以有:

                   if(i== 4)   

                            left= i, right = 0;

                   else

                            left= i, right = i+1;

         振荡:如果每个人都攥着自己左手的锁,尝试去拿右手锁,拿不到则将锁释放。过会儿五个人又同时再攥着左手锁尝试拿右手锁,依然拿不到。如此往复形成另外一种极端死锁的现象——振荡。

         避免振荡现象:只需5个人中,任意一个人,拿锁的方向与其他人相逆即可(如:E,原来:左:4,右:0 现在:左:0, 右:4)。

         所以以上if else语句应改为:

                   if(i== 4)   

                            left= 0, right = i;

                   else

                            left= i, right = i+1;

         而后,首先应让哲学家尝试加左手锁: 

while {

                            pthread_mutex_lock(&m[left]);     如果加锁成功,函数返回再加右手锁,

                                                                                             如果失败,应立即释放左手锁,等待。

                            若,左右手都加锁成功--> 吃 --> 吃完 --> 释放锁(应先释放右手、再释放左手,是加锁顺序的逆序)

                   }

         主线程(main)中,初始化5把锁,销毁5把锁,创建5个线程(并将i传递给线程主函数),回收5个线程。

避免死锁的方法:

         1. 当得不到所有所需资源时,放弃已经获得的资源,等待。

         2. 保证资源的获取顺序,要求每个线程获取资源的顺序一致。如:A获取顺序1、2、3;B顺序应也是1、2、3。若B为3、2、1则易出现死锁现象。                                                                                                      

多进程版

相较于多线程需注意问题:

         需注意如何共享信号量 (注意:坚决不能使用全局变量 sem_t s[5])

实现:

         main函数中:       

循环sem_init(&s[i], 0, 1); 将信号量初值设为1,信号量变为互斥锁。

                   循环 sem_destroy(&s[i]);

                   循环创建 5 个子进程。 if(i < 5) 中完成子进程的代码逻辑。

                   循环回收 5 个子进程。

         子进程中:

if(i == 4) 

left = 0, right == 4;

                   else 

left = i, right = i+1;  

                   while(1) {

                            使用sem_wait(&s[left]) 锁左手,尝试锁右手,若成功 --> 吃;若不成功 --> 将左手锁释放。

                            吃完后, 先释放右手锁,再释放左手锁。

                   }

【重点注意】:

直接将sem_t s[5]放在全局位置,试图用于子进程间共享是错误的!应将其定义放置与mmap共享映射区中。main中:

sem_t *s =mmap(NULL, sizeof(sem_t) * 5, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANON, -1, 0);

         使用方式:将s当成数组首地址看待,与使用数组s[5]没有差异。     



#include 
   
   
    
    
#include 
    
    
     
     
#include 
     
     
      
      
#include 
      
      
       
       

pthread_mutex_t m[5];

void *tfn(void *arg)
{
	int i, l, r;

	srand(time(NULL));
	i = (int)arg;

	if (i == 4)
		l = 0, r = i;
	else
		l = i; r = i+1;

	while (1) {
		pthread_mutex_lock(&m[l]);
		if (pthread_mutex_trylock(&m[r]) == 0) {
			printf("\t%c is eating \n", 'A'+i);
			pthread_mutex_unlock(&m[r]);
		}
		pthread_mutex_unlock(&m[l]);
		sleep(rand() % 5);
	}

	return NULL;
}

int main(void)
{
	int i;
	pthread_t tid[5];
	
	for (i = 0; i < 5; i++)
		pthread_mutex_init(&m[i], NULL);

	for (i = 0; i < 5; i++)
		pthread_create(&tid[i], NULL, tfn, (void *)i);

	for (i = 0; i < 5; i++)
		pthread_join(tid[i], NULL);

	for (i = 0; i < 5; i++)
		pthread_mutex_destroy(&m[i]);

	return 0;
}


      
      
     
     
    
    
   
   


                                  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值