哲学家用餐模型分析
来源:互联网 发布:虹越400官网和淘宝店 编辑:程序博客网 时间:2024/04/28 22:22
#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;elsel = 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;}
多线程版:
#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;elsel = 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;elsel = 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;}
- 哲学家用餐模型分析
- 哲学家用餐模型分析
- Linux 多线程同步之哲学家用餐问题分析
- 哲学家用餐问题(Java)
- Linux 多线程同步之哲学家用餐问题
- linux多线程【3】哲学家用餐-mutex实现
- linux多线程【4】哲学家用餐-sem_t
- linux多线程【5】哲学家用餐-另一种思路
- Linux 多线程同步之哲学家用餐问题
- Linux 多线程同步之哲学家用餐问题
- 哲学家就餐模型
- java 线程 死锁(哲学家用餐案例讲解) -------thinking java 4
- 【经典操作系统问题】哲学家就餐问题分析
- 哲学家就餐问题的分析与解决方案
- Prince 老师,用餐演讲
- 李嘉诚用餐之道
- 分析模型
- 对话:如何选择商务用餐
- iOS 数组的排序(升序、降序、乱序)
- Swift中的struct与class
- 利用断点流实现继续下载(实际就是利用断点流seek()方法)
- 动态数码管显示
- BZOJ 4503: 两个串 FFT 通配符匹配
- 哲学家用餐模型分析
- UDP组播
- 距离秋招还有一个月了
- 队列
- PAT --- 1001. 害死人不偿命的(3n+1)猜想
- Ubuntu的版本介绍
- 自我激励
- VS2017中添加QWebEngineView模块
- shoeBox超实用的雪碧图(Sprite)图制作工具-使用shoeBox