System V 信号量(三)之用信号量解决哲学家进餐问题
来源:互联网 发布:asp数据库导出excel 编辑:程序博客网 时间:2024/06/06 05:34
一.哲学家就餐问题
5个哲学家,5个筷子。5个哲学家围坐在一张桌子上,筷子放在分别放在每个哲学家的两旁。如果所有哲学家在某个时刻同时拿起左边的筷子,那么右边的筷子就都被其他的哲学家拿了,造成大家都无法吃饭。但是大家都不想放下左边的筷子(规则是先拿起左边筷子在拿起右边的,吃完饭在放下左,再放下右),这就是死锁。
解决这个问题有个办法是在拿起筷子前先判断左右两个筷子是否可用,可用才能拿,而且是同时拿,这样不相邻的哲学家就可以吃上饭,不会造成死锁。
用伪代码描述下5位哲学家主要做的事,暂时还没有考虑死锁问题.
程序中,哲学家编号为0-4,筷子编号也为0到4
void philosopher(int i) // i:哲学家编号,从0到4
{
while(TRUE)
{
think(); // 哲学家思考
take_fork(i); //饿了,拿起左筷子
take_fork((i+1)%N); // 拿起右筷子
eat(); // 进食
put_fork(i); // 放下左筷子
put_fork((i+1)%N); // 放下右筷子
}
}
二.用信号量解决哲学家就餐问题
容易出现死锁用的是记录型信号量,伪代码为:
semaphore chopstick chopstick[5] = {1,1,1,1,1};
do
{
//think
wait(chopstick[i]);
wait(chopstick[(i+1)%5]);
//eat
signal(chopstick[i]);
signal(chopstick[(i+1)%5]);
}while(true)
semaphore chopstick chopstick[5] = {1,1,1,1,1};
do
{
//think
Sswait(chopstick[i],chopstick[(i+1)%5]);
//eat
Ssignal(chopstick[i],chopstick[(i+1)%5]);
}while(true)
<pre name="code" class="cpp">#include <stdio.h>#include <stdlib.h>#include <string.h>#include <stdint.h>#include <stdbool.h>#include <errno.h> #include <unistd.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/ipc.h>#include <sys/sem.h>#include <sys/wait.h> union semun{ int val; struct semid_ds *buf; unsigned short *array; struct seminfo *__buf;}; #define ERR_EXIT(m) \ do { \ perror(m); \ exit(EXIT_FAILURE); \ } while(0) //申请一个资源intwait_1fork(int no,int semid){ //int left = no; //int right = (no + 1) % 5; struct sembuf sb = {no,-1,0}; int ret; ret = semop(semid,&sb,1); if(ret < 0) { ERR_EXIT("semop"); } return ret;} // 释放一个资源int free_1fork(int no,int semid){ struct sembuf sb = {no,1,0}; int ret; ret = semop(semid,&sb,1); if(ret < 0) { ERR_EXIT("semop"); } return ret;} //这里表明叉子是一个临界资源#define DELAY (rand() % 5 + 1)//相当于P操作void wait_for_2fork(int no,int semid){ //哲学家左边的刀叉编号和哲学家是一样的 int left = no; //右边的刀叉 int right = (no + 1) % 5; //刀叉值是两个 //注意第一个参数是编号 //操作的是两个信号量,即两种资源都满足,才进行操作 struct sembuf buf[2] = { {left,-1,0}, {right,-1,0} }; //信号集中有5个信号量,只是对其中的资源sembuf进行操作 semop(semid,buf,2);} //相当于V操作 ,释放刀叉void free_2fork(int no,int semid){ int left = no; int right = (no + 1) % 5; struct sembuf buf[2] = { {left,1,0}, {right,1,0} }; semop(semid,buf,2);} //哲学家要做的事void philosophere(int no,int semid){ srand(getpid()); //srand(time(NULL)); for(;;) { #if 1 //这里采取的措施是当两把刀叉都可用的时候(即两种资源都满足的时候) //哲学家才能吃饭,这样不相邻的哲学家就可吃上饭 printf("%d is thinking\n",no); // 思考中 sleep(DELAY); printf("%d is hungry\n",no); // 感觉到饥饿 wait_for_2fork(no,semid);//拿到两把叉子才能吃饭 printf("%d is eating\n",no); // 吃饭 sleep(DELAY); free_2fork(no,semid);//释放两把叉子 #else //这段代码可能会造成死锁 int left = no; int right = (no + 1) % 5; printf("%d is thinking\n",no); // 思考中 sleep(DELAY); printf("%d is hungry\n",no); // 感觉到饥饿 wait_1fork(left,semid); // 拿起左叉子,现在是只要有一个资源,就申请 sleep(DELAY); wait_1fork(right,semid); // 拿到右叉子 printf("%d is eating\n",no); // 吃饭 sleep(DELAY); free_1fork(left,semid); // 释放左叉子 free_1fork(right,semid); // 释放右叉子 #endif }} int main(int argc,char *argv[]){ int semid; //创建信号量 //信号量集中5个信号量 semid = semget(IPC_PRIVATE,5,IPC_CREAT | 0666); if(semid < 0) { ERR_EXIT("semid"); } union semun su; su.val = 1; int i; for(i = 0;i < 5;++i) { //注意第二个参数也是索引 semctl(semid,i,SETVAL,su); } //创建4个子进程 int num = 0; pid_t pid; for(i = 1;i < 5;++i) { pid = fork(); if(pid < 0) { ERR_EXIT("fork"); } if(0 == pid) // 子进程 { num = i; break; } } //这里就是哲学家要做的事情 philosophere(num,semid); return 0;}
一直运行,代表不出现死锁:
修改101行代码为 #if 0 ,演示出现死锁现象,如果没有出现,多运行几次试试
相关参考:
<<计算机操作系统>>西安电子科技出版社(第四版) 64页
- System V 信号量(三)之用信号量解决哲学家进餐问题
- 信号量 哲学家进餐问题
- linux网络编程之System V 信号量(二):用信号量实现进程互斥示例和解决哲学家就餐问题
- linux网络编程之System V 信号量(二):用信号量实现进程互斥示例和解决哲学家就餐问题
- 用信号量解决哲学家就餐问题
- Operating System-进程/线程内部通信-信号量、PV操作的实现和应用(解决哲学家进餐和生产者消费者问题)
- 哲学家问题 POSIX 信号量
- 2、System V 信号量
- system V信号量
- 信号量(System V)
- System V 信号量
- System V 信号量2
- System V 信号量
- Linux System V 信号量
- System V 信号量(一)
- System V 信号量(二)
- 关于System V 信号量
- system V信号量
- linux 查看电脑配置信息
- c# 微信支付,问题及解决
- 运用JS设置cookie、读取cookie、删除cookie
- zookeeper
- 顺时针打印矩阵(C语言代码)
- System V 信号量(三)之用信号量解决哲学家进餐问题
- 解决win8/8.1程序不能以管理员权限自动启动问题
- 利用DCC 工具调节AWB
- 通过ajax引擎对象向服务器发送数据的2中方式:get、post
- 栈和队列--第3集
- caffe训练数据时,accuracy 一直是0
- 使用git工具,在本地建立一个数据仓库,保存日常工作日志
- I帧和IDR帧
- 文章而产生的e标题