哲学家进餐问题:
- 在什么情况下5 个哲学家全部吃不上饭?
假如所有的哲学家都同时拿起左侧筷子,看到右侧筷子不可用,又都放下左侧筷子,
等一会儿,又同时拿起左侧筷子,如此这般,永远重复。对于这种情况,即所有的程序都在
无限期地运行,但是都无法取得任何进展,即出现饥饿,所有哲学家都吃不上饭。 这里给出一种避免死锁的解决方式。
最多只允许四个哲学家同时进餐,以保证至少有一个哲学家能够进餐,最终总会释
放出他所使用过的两支筷子,从而可使更多的哲学家进餐。
以下将room 作为信号量,只允 许4 个哲学家同时进入餐厅就餐,这样就能保证至少有一个哲学家可以就餐,而申请进入
餐厅的哲学家进入room 的等待队列,根据FIFO 的原则,总会进入到餐厅就餐,因此不会 出现饿死和死锁的现象。下面给出详细的 C代码实现。
头文件
#pragma once
#include <stdio.h>
#include <tchar.h>
#include <process.h>
#include <stdlib.h>
#include <Windows.h>
#include <time.h>
#include <math.h>
#include <GLAUX.H>
#include <gl/GL.h>
#include <gl/GLU.h>
#include <gl/glut.h>
#include <SDKDDKVer.h>
主程序代码
#include "stdafx.h"
HANDLE chopstick[5],room;
LPCRITICAL_SECTION cs;
const GLfloat Pi = 3.1415926536f;
const GLfloat R = 10.0f;
//五个中心的坐标
const GLfloat x[5] = { 200, 105, 141, 259, 295 };
const GLfloat y[5] = { 300, 231, 119, 119, 231 };
//代表5个哲学家的状态,0表示思考,1表示吃饭,2表示等待
int state[5] = { 0, 0, 0, 0, 0 };
void initchopstick(){
for (int i = 0; i < 5; i++){
chopstick[i] = CreateSemaphore(NULL, 1, 1, TEXT("chopstick"+i));
}
room = CreateSemaphore(NULL, 4, 4, TEXT("room"));
}
int srandNum(){
srand(time(0));
return (rand() % 100);
}
void think(int i){
printf("哲学家%d正在思考\n", i);
state[i] = 0;
Sleep((DWORD(srandNum() % 10000+2000)));
}
void eat(int i){
printf("哲学家%d正在吃饭\n", i);
state[i] = 1;
Sleep((DWORD(srandNum() % 10000+2000)));
}
void philosopher(PVOID p)
{
int i = (int)p;
while (true)
{
think(i);
//等待状态
state[i] = 2;
WaitForSingleObject(room, INFINITE);
WaitForSingleObject(chopstick[i], INFINITE);//请求左手边的筷子
WaitForSingleObject(chopstick[(i + 1) % 5], INFINITE);//请求右手边的筷子
EnterCriticalSection(cs);
eat(i);
LeaveCriticalSection(cs);
Sleep(500);
ReleaseSemaphore(chopstick[(i + 1) % 5],1,NULL); //释放右手边的筷子
ReleaseSemaphore(chopstick[i],1,NULL); //释放左手边的筷子
ReleaseSemaphore(room,1,NULL); //退出房间释放信号量room
}
}
// 函数RenderScene用于在窗口中绘制需要的图形
void RenderScene(void)
{
//用当前清除色清除颜色缓冲区,即设定窗口的背景色
glClear(GL_COLOR_BUFFER_BIT);
for (int i = 0; i < 5; i++){
//设置当前绘图使用的RGB颜色
if (state[i] == 2){
glColor3f(1.0f, 1.0f, 0.0f);//黄色代表等待
}
else if (state[i] == 1){
glColor3f(0.0f, 1.0f, 0.0f);//绿色代表吃饭
}
else if (state[i] == 0){
glColor3f(1.0f, 0.0f, 0.0f);
}
glRectf(x[i] - R, y[i] - R, x[i] + R, y[i] + R);
}
//清空命令缓冲区并交换帧缓存
glutSwapBuffers();
}
// 函数ChangeSize是窗口大小改变时调用的登记函数
void ChangeSize(GLsizei w, GLsizei h)
{
if (h == 0) h = 1;
//设置视区尺寸
glViewport(0, 0, w, h);
// 重置坐标系统,使投影变换复位
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// 建立修剪空间的范围
if (w <= h)
glOrtho(0.0f, 400.0f, 0.0f, 400.0f*h / w, 1.0f, -1.0f);
else
glOrtho(0.0f, 400.0f*w / h, 0.0f, 400.0f, 1.0f, -1.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void TimerFunction(int value)
{
glutPostRedisplay();
glutTimerFunc(33, TimerFunction, 1);
}
void SetupRC(void)
{
//设置窗口清除色为蓝色
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
}
int _tmain(int argc, _TCHAR* argv[])
{
initchopstick();
cs = (LPCRITICAL_SECTION)malloc(sizeof(LPCRITICAL_SECTION));
InitializeCriticalSection(cs);
for (int i = 0; i < 5; i++){
_beginthread(philosopher, NULL, (PVOID)i);
}
glutInitDisplayMode(GLUT_RGB |GLUT_DOUBLE);
glutInitWindowSize(800, 800);
glutCreateWindow("Draw");
glutDisplayFunc(RenderScene);
glutReshapeFunc(ChangeSize);
glutTimerFunc(33, TimerFunction, 1);
SetupRC();
glutMainLoop();
Sleep(INFINITE);
DeleteCriticalSection(cs);
return 0;
}