5.线程与并发同步-哲学家用餐模型分析

多线程版:
选用互斥锁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则易出现死锁现象。

多线程

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>

#define NUM 5

int num=100;
pthread_mutex_t mutex[NUM];


void *fun(void*arg){
	int i=*(int*)arg;
	int left,right;
	while(1){
		srand((unsigned int)time(NULL));
		if(i == 4)	
			left = 0, right = i;
		else 
			left = i, right = i+1;
		pthread_mutex_lock(&mutex[left]);
		printf("%d,%ld, get mutex = %d\n",i,pthread_self(),left);
		sleep(rand()%2+1);//等待一下
		int r=pthread_mutex_trylock(&mutex[right]);
		if(r==0)//两边的锁都获得,吃饭
		{
			printf("%d,%ld,eating %d, get mutex = %d,%d\n",i,pthread_self(),--num,left,right);
			pthread_mutex_unlock(&mutex[right]);//释放右锁
		}
		else{//获取右锁失败,思考
			printf("%d,%ld,thinking, give up mutex = %d\n",i,pthread_self(),left);
		}
		pthread_mutex_unlock(&mutex[left]);//释放左锁
		sleep(rand()%2+2);
	}

}

int main(){
	pthread_t pt[NUM];
	int i;
	for(i=0;i<NUM;i++)
		pthread_mutex_init(&mutex[i], NULL);
	for(i=0;i<NUM;i++){
		pthread_create(&pt[i],NULL,fun,(void*)&i);
		usleep(1);
	}	
	for(i=0;i<NUM;i++){
		pthread_join(pt[i],NULL);
	}
	for(i=0;i<NUM;i++){
		pthread_mutex_destroy(&mutex[i]);
	}	
	return 0;
}

0,140226396456704, get mutex = 0
1,140226320135936, get mutex = 1
2,140226311743232, get mutex = 2
3,140226303350528, get mutex = 3
0,140226396456704,thinking, give up mutex = 0
4,140226294957824, get mutex = 0
1,140226320135936,thinking, give up mutex = 1
2,140226311743232,thinking, give up mutex = 2
3,140226303350528,eating 99, get mutex = 3,4
4,140226294957824,eating 98, get mutex = 0,4
1,140226320135936, get mutex = 1
2,140226311743232, get mutex = 2
3,140226303350528, get mutex = 3
0,140226396456704, get mutex = 0
2,140226311743232,thinking, give up mutex = 2
3,140226303350528,eating 97, get mutex = 3,4
0,140226396456704,thinking, give up mutex = 0
1,140226320135936,eating 96, get mutex = 1,2
4,140226294957824, get mutex = 0
1,140226320135936, get mutex = 1
4,140226294957824,eating 95, get mutex = 0,4
3,140226303350528, get mutex = 3
0,140226396456704, get mutex = 0
2,140226311743232, get mutex = 2
1,140226320135936,thinking, give up mutex = 1
^C

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值