用P、V操作写出一个不会出现死锁的哲学家进餐问题

如题所述

哲学家就餐问题是一种典型的同步问题,它是由Dijkstra 提出并解决的。该问题描述
:有五个哲学家,他们的生活方式是交替的进行思考和进餐。哲学家们共用一张圆桌,
查看图片
设五个哲学家分别编号为A,B,C,D,E,桌子上放着五把筷子,筷子分别编号为 0,1,
2,3,4,桌子中央有一盘饭菜。五个哲学家都很有礼貌,都要等同时拿到身旁的两只筷子
才进餐,不然就只是等着继续思考,而且吃了一口之后又马上放下拿起的两根筷子,继续思
考。
用P V原语的方式实现

每个哲学家可用一个线程来模拟,信号量及其P、V操作的实现
定义一个semaphore 类 封装 P V原语模拟函数

(不妨设有6个哲学家,6只筷子, 每只筷子各对应一个信号量且每个信号量初始值应为1)/***********************semaphore.h*****************************
Semaphore类用于模拟信号量
用法如:Semaphore sem(1);
(1)要求初始信号量值非负
(2)信号量P操作: sem.P();
(3)信号量V操作: sem.V();
#ifndef SEMAPHORE_H
#define SEMAPHORE_H
#include <windows.h>
class Semaphore{
protected:
HANDLE sem;
public:
//Semaphore();
//void SetValve(int SemValue);
Semaphore(unsigned int SemValue);
virtual ~Semaphore();
void P();
void V();
#endif
/*****************************semaphore.cpp************************************/
#include <windows.h>
#include <LIMITS.H>
#include <assert.h>
#include "semaphore.h"
Semaphore::Semaphore(unsigned int semValue){
if(semValue > LONG_MAX)
semValue = LONG_MAX;
sem = CreateSemaphore(NULL,semValue,LONG_MAX,NULL);
Semaphore::~Semaphore(){
CloseHandle(sem);
void Semaphore::P(){
DWORD dw = WaitForSingleObject(sem, INFINITE);
assert(dw == WAIT_OBJECT_0);
void Semaphore::V(){
ReleaseSemaphore(sem,1,NULL);
/*****************************thread.h*************************************
通过startThread开启线程
startThread(PTHREAD_START func,void * param);
用法:
//定义一个PTHREAD_START类型的函数func
unsigned int WINAPI func (void * param){
//启动一个线程使其执行func函数
startThread(func,NULL);
#ifndef THREAD_H
#define THREAD_H
#include <windows.h>
#include <process.h>
from MSDN :
Start address of a routine that begins execution of a new thread.
For _beginthread, the calling convention is either __cdecl or __clrcall;
for _beginthreadex, it is either __stdcall or __clrcall.
WINAPI即为__stdcall
typedef unsigned int (WINAPI *PTHREAD_START) (void *);
chBEGINTHREADEX is From <Windows Via C & C++>
#define chBEGINTHREADEX(psa, cbStackSize, pfnStartAddr, \
pvParam, dwCreateFlags, pdwThreadId) \
((HANDLE)_beginthreadex( \
(void *) (psa), \
(unsigned) (cbStackSize), \
(PTHREAD_START) (pfnStartAddr), \
(void *) (pvParam), \
(unsigned) (dwCreateFlags), \
(unsigned *) (pdwThreadId)))
// rename chBEGINTHREADEX to startThread for simplicity
#define startThread(pfnStartAddr,pvParam)\
chBEGINTHREADEX(NULL, 0, (pfnStartAddr),(pvParam), 0, NULL)
#endif
/*****************************main函数(主函数)************************************/
假设偶数号哲学家先拿左边的筷子,右边的哲学家先拿起右边的筷子。
#include <windows.h>
#include "semaphore.h"
#include "thread.h"
#include <iostream.h>
#include <stdio.h>
#define N 6 //哲学家的个数
#define LEFT(i) (i+N-1)%N //左边的筷子
#define RIGHT(i) (i==N-1)?0:(i+N)%N //右边的筷子 编号为N的哲学家的右边的筷子编号为0
/*******************************初始化信号量**************************************/
Semaphore ChopStick[N]={Semaphore(1),Semaphore(1),Semaphore(1),Semaphore(1),Semaphore(1),Semaphore(1)} ;
/*******************************哲学家状态*******************************************/
void Eating(int Ph_Id)
printf("Philosopher%d: \tI'm eating......\t",(int)Ph_Id);
void Sleeping(int Ph_Id)
printf("Philosopher%d:\tI'm sleeping......\t",(int)Ph_Id);
Sleep(rand()%10000);
void Thinking(int Ph_Id)
printf("Philosopher%d: \tI'm thinking......\t",(int)Ph_Id);
if (pid%2 == 0) //偶数号哲学家
Thinking(pid); //等待中
ChopStick[LEFT(pid)].P(); //先拿起左边的筷子,再拿起右边的筷子
ChopStick[RIGHT(pid)].P();
Eating(pid); //获得的两个信号量则eating
ChopStick[LEFT(pid)].V(); //先后释放左右信号量
ChopStick[RIGHT(pid)].V();
printf("\n");
else if(pid%2==1 ) //奇数号哲学家
Thinking(pid);
ChopStick[RIGHT(pid)].P(); //先拿起右边的筷子,再拿起左边的筷子
ChopStick[LEFT(pid)].P();
Eating(pid); //左右都得到筷子后则eating
ChopStick[RIGHT(pid)].V(); //先后释放右左信号量
ChopStick[LEFT(pid)].V();
printf("\n");
Sleeping(pid); //吃完睡上一会儿
int main(){
HANDLE hPhilosopher[N]; //为每个哲学家分配一个线程
int count =0 ;
for (int Philosopher_id =0 ;Philosopher_id<N;Philosopher_id++) //开启线程
hPhilosopher[Philosopher_id] = startThread(Philosopher,Philosopher_id);
if(count>5)
break;
::WaitForMultipleObjects(N,hPhilosopher,TRUE,INFINITE);
for (Philosopher_id = 0 ; Philosopher_id<N;Philosopher_id++)
CloseHandle(hPhilosopher[Philosopher_id]);
温馨提示:内容为网友见解,仅供参考
无其他回答

哲学家就餐问题
两个地方应该是pv操作,pv都是操作元语,不可中断 p操作是将信号量-1 v操作是将信号量+1 pv一定要配对使用 哲学家进餐可以通过信号量机制解决,避免死锁 注释如下:Void test(int i) \/\/测试哲学家i是否满足eating条件 { if(state[i]==HUNGRY) \/\/状态为hungry且左右均未在eating状态,即...

哲学家进餐问题(在计算机操作系统方面的相关编程)
许4 个哲学家同时进入餐厅就餐,这样就能保证至少有一个哲学家可以就餐,而申请进入餐厅的哲学家进入room 的等待队列,根据FIFO 的原则,总会进入到餐厅就餐,因此不会出现饿死和死锁的现象。伪码:semaphore chopstick[5]={1,1,1,1,1};semaphore room=4;void philosopher(int i){while(true){think();wait(room)...

哲学家就餐问题
哲学家的思考、进餐和放下筷子的过程,都会在加锁(P(mutex))和解锁(V(mutex))之间进行。在尝试获取或释放筷子前,哲学家会先检查自己的饥饿状态以及左右邻座的信号状态。只有在所有条件满足后,才能继续进行下一步操作,确保避免死锁。当用餐结束后,哲学家会释放信号量,允许其他哲学家有机会获取筷...

哲学家就餐问题与死锁总结
先写一个会造成死锁的哲学家问题。当所有哲学家同时决定进餐,拿起左边筷子时候,就发生了死锁。解决方案一:破坏死锁的 循环等待条件 。 不再按左手边右手边顺序拿起筷子。选择一个固定的全局顺序获取,此处给筷子添加id,根据id从小到大获取,(不用关心编号的具体规则,只要保证编号是全局唯一并且有序...

关于哲学家进餐问题。。。
:“因为中国原有的语汇不够用,现在我们的语汇中就有很多是从外国吸收来的,例如今天开的干部大会,这干部二字就是从国外学来的,我们还要多吸收外国新鲜的东西,不但要吸收它们进步的理论,还要吸收他们的新鲜用语”外国人也是这么学来的,可能就是因为没用过,觉得筷子新鲜,然后遇到困难就联想到筷子也不好弄...

经典哲学家进餐问题
此问题与“生产者消费者”、“吸烟问题”、“读者写者问题”等不同,其根源在于每个哲学家操作了两个共享资源。为避免死锁,需要的筷子数量为n(k-1)+1,即6根筷子,以确保系统正常运行。为破解死锁,我们提出三种解决方案。首先,仅当左侧和右侧筷子均可用时,哲学家才能取筷子进食。通过设置互斥量...

哲学家就餐问题
试问:1)描述一个保证不会出现两个邻座同时要求吃饭的算法;2)描述一个既没有两邻座同时吃饭,又没有人饿死的算法;3)在什么情况下,5个哲学家全都吃不上饭?哲学家进餐问题是典型的同步问题.它是由Dijkstra提出并解决的.该问题是描述有五个哲学家,他们的生活方式是交替地进行思考和进餐.哲学家们共用一...

用记录型信号量解决哲学家进餐问题
27.试利用记录型信号量写出一个丌会出现死锁的哲学家迚餐问题的算法. 答:Var chopstick:array[0,„,4] of semaphore;所有信号量均被初始化为1,第i 位哲学家的活动可描述为: Repeat Wait(chopstick[i]);Wait(. chopstick[(i+1) mod 5]); „ Ea.t „Signal...

哲学家进餐问题的问题描述
(2)如果筷子已被别人拿走,则必须等别人吃完之后才能拿到筷子。(3)任一哲学家在自己未拿到两只筷子吃饭前,不会放下手中拿到的筷子。信号量机制筷子是临界资源,一段时间只允许一位哲学家使用。为了表示互斥,用一个信号量表示一只筷子,五个信号量构成信号量数组。本文中算法用类C语言描述伪码算法。...

...型信号量写出一个不会出现死锁的哲学家进餐问题的算法.请各位高手们...
Var chopstick:array[0,…,4] of semaphore;void philosopher(int I){ while(true){ think();Swait(chopstick[(I+1)]%5,chopstick[I]);eat();Ssignal(chopstick[(I+1)]%5,chopstick[I]);} }

相似回答