哲学家就餐问题-预备知识及深入探讨
来源:互联网 发布:java程序员适合mac吗 编辑:程序博客网 时间:2024/06/06 21:52
/* created by Herbert on 16 Nov,2017 预备知识: 信号量:信号量是管理相应临界区的公有资源,它代表可用资源实体。 在操作系统中,信号量sem是一个整数。在sem大于等于零时代表 可供并发进程使用的资源实体的数目,但sem小于零时则代表则代表 等待使用临界区的进程的数目。 sem的初始值应该大于零,在建立一个信号量的时候,必须说明信号量 的代表的意义,以及建立相应的数据结构,以便指向那些等待使用该 临界区的进程。 P、V原语: 信号量的数值仅能由P、V的操作改变(P代表 pass,V代表 increment) 一次P原语操作使得信号量sem减一,一次V原语操作使得信号量sem加一 问题描述:设有五个哲学家,共享一张放有五把椅子的桌子,没人分得一把椅子。但是,桌子上 总共有五支筷子,在每人两边分开各放一支。哲学家们在肚子饥饿时才会试图分两次从两边拾起筷子 就餐。 条件如下: (1)只有拿到两支筷子时,哲学家才能吃饭。 (2)如果筷子已经在他人手上,则该哲学家必须等到他人吃完之后才能拿到筷子。 (3)任一哲学家在自己未拿到两支筷子吃饭之前,绝不放下自己手中的筷子。 试: (1)描述一个保证不会出现两个邻座同时要求吃饭的通信算法 (2)描述一个既没有两邻座同时吃饭,又没有人饿死(永远拿不到筷子)的算法。 (3)在什么情况下,五个哲学家全部吃不上饭。*//* 解答: (1) 设信号量c[0]~c[4],初始值均为1,分别表示I号筷子被拿(I=0,1,2,3,4)。 send(I):第I个哲学家要吃饭 begin: P(c[i]); P(c[I+1 mod 5]); eat; V(c[I+1 mod 5]); V(c[I]); end 该过程能保证两邻座不同时吃饭,但会出现五个哲学家一人拿一支筷子,谁也吃不上饭的死锁情形。 (2) 解决的思路如下: 让奇数号的哲学家先取右手边的筷子,让偶数号的哲学家先取左手边的筷子。这样,任何一个哲学家 拿到一支筷子后,就已经阻止了他邻座的一个哲学家吃饭的企图,除非某个哲学家一直吃下去,否则不会有人 饿死。 send(I): begin if I mod 2 == 0 then { P(c[I]); P(c[I+1] mod 5); eat; V(c[I]); V(c[I+1] mod 5); } else { P(c[I+1 mod 5]); P(c[I]); eat; V(c[I+1 mod 5]); V(c[I]); } end (3) 一人拿一支筷子时所有人都吃不上饭。*//*让奇数号的哲学家先取右手边的筷子,让偶数号的哲学家先取左手边的筷子。这样,任何一个哲学家拿到一支筷子后,就已经阻止了他邻座的一个哲学家吃饭的企图,除非某个哲学家一直吃下去,否则不会有人饿死。While(true){ if( i % 2 == 0){ //偶数号哲学家 P(左边筷子对应的信号量) P(右边筷子对应的信号量) 拿起两只筷子吃饭 V(右边筷子对应的信号量) V(左边筷子对应的信号量) }else{ //奇数号哲学家 P(右边筷子对应的信号量) P(左边筷子对应的信号量) 拿起两只筷子吃饭 V(左边筷子对应的信号量) V(右边筷子对应的信号量) } 吃饱后思考 } *//*int sem_init(sem_t *sem,int pshared,unsigned int value);// sem_init用于对指定信号初始化,pshared为0, 表示信号在当前进程的多个线程之间共享,value表示初始化信号的值。 int sem_wait(sem_t *sem); sem_wait可以用来阻塞当前线程,直到信号量的值大于0,解除阻塞。 解除阻塞后,sem的值-1,表示公共资源被执行减少了。 例如:如果你对一个值为2的信号量调用sem_wait(),线程将会继续执行, 信号量的值将-1。当初始化value=0后,使用sem_wai会阻塞这个线程, 这个线程函数就会等待其它线程函数调用int sem_post(sem_t *sem); sem_post用于增加信号量的值+1,当有线程阻塞在这个信号量上时, 调用这个函数会使其中的一个线程不在阻塞,选择机制由线程的调度策略决定。 */#include <iostream>#include <unistd.h>#include <pthread.h>#include <semaphore.h>#include <cstdio>#define N 5//哲学家人数#define LEFT i#define RIGHT (i+1)%Nusing namespace std;class Semaphore { //定义Semaphore类private: sem_t sem; //定义信号量public: Semaphore(int value = 1) { sem_init(&sem,0,value); //初始化信号量,0表示信号量在线程间共享 } void P() { sem_wait(&sem); //等待信号,获取拥有权 } void V() { sem_post(&sem); //释放信号,释放拥有权 } }; Semaphore mutex[N];//定义N个信号量pthread_t thread[N];//定义N个线程int id[N];void *solve(void* param);//解决算法void thread_create();//进程创建void thread_wait();//进程等待int main(){ for(int i = 0; i < N; i++) { id[i] = i; //为哲学家编号 } thread_create(); thread_wait(); return 0;}void *solve(void* param){ int i = *((int *)param); while(true){ if(i % 2 == 0){//如果是偶数,则先取左手边的筷子 mutex[LEFT].P(); mutex[RIGHT].P(); cout<<"哲学家"<<i<<"吃饭"<<endl; mutex[RIGHT].V(); mutex[LEFT].V(); } else{//如果是奇数,则先取右手边的筷子 mutex[RIGHT].P(); mutex[LEFT].P(); cout<<"哲学家"<<i<<"吃饭"<<endl; mutex[LEFT].V(); mutex[RIGHT].V(); } sleep(1); } pthread_exit(NULL);}void thread_create() { //进程创建 int tmp; for(int i = 0; i < N; i++) { tmp = pthread_create(&thread[i],NULL,solve,&id[i]); if(tmp != 0) { cout<<"线程"<<i<<"创建失败"<<endl; } } } void thread_wait() { //进程等待 for(int i = 0; i < N; i++) { pthread_join(thread[i],NULL); printf("线程%d结束\n",i); } }
阅读全文
0 0
- 哲学家就餐问题-预备知识及深入探讨
- 哲学家就餐问题
- 哲学家就餐问题
- 哲学家就餐问题
- 哲学家就餐问题 锁
- 哲学家就餐问题
- 哲学家就餐问题
- 关于哲学家就餐问题
- 哲学家就餐问题
- 哲学家就餐问题
- 哲学家就餐问题
- 哲学家就餐问题
- 哲学家就餐问题
- 哲学家就餐问题
- 哲学家就餐问题
- 哲学家就餐问题
- 哲学家就餐问题
- 哲学家就餐问题
- #define和inline的区别 sizeof与strlen的区别 以及运算符函数关键字三种概念
- linux下常用的命令
- 转载:总结使用libwebsockets
- 第十题 二分查找 还是有好多错误
- 交叉熵代价函数定义及其求导推导(读书笔记)
- 哲学家就餐问题-预备知识及深入探讨
- KMP 入门水题 hdu 2087 剪花布条
- position:relative;top属性移动div后的空白怎么去掉?
- 【object window】= $0
- POJ
- java方向
- 一些看起来很特殊的for循环代码,以及sizeof和strlen代码运行机制,还有#define
- AndroidStudio中修改项目名称和包名
- 链栈实现数制的转换