哲学家就餐问题(uc/OS II)

哲学家就餐问题

    五个哲学家,共用一张圆桌,分别坐在周围的5张椅子上,在圆桌上有5个碗和五支筷子,平时哲学家进行思考,饥饿时便试图取其左、右靠近他的筷子,只有在他拿到两只筷子时才能进餐。进餐完后,放下筷子思考。

要求:

    1、键盘上的按键1-5分别代表5个哲学家申请吃饭

    2、要求列出所有可能出现的状况,而且屏幕上必须将最新状态显示出来

   (1)哲学家i正在进餐,哲学家i对应的状态显示为“Philos i is eating”,并显示进餐完毕倒计时

   (2) 哲学家i申请进餐未果,哲学家i对应的状态显示为“Philos i apply for meal failed”,并且等待5秒。       

     若5秒内拿到了筷子,状态改为“Philos i is eating”,并显示进餐完毕倒计时;若5秒内没拿到筷子,则显示"Philos i       is thinking "

   (3) 哲学家i正在思考,哲学家i对应的状态显示为"Philos i is thinking "

    3、每位哲学家进餐时间可变,进餐次数不限(程序能一直运行)


基本思路

    不申请吃饭时,显示"Philos i is thinking ";按下相应按键(1-5)申请吃饭时,先显示“Philos i apply for meal failed”,再在等待的5s内判断是否拿到了两根筷子,左右两根都拿到了则显示“Philos i is eating”,没拿到两根则不改变显示。

实现

    信号量

    创建5个信号量来代表5根筷子。创建7个任务,5个任务为哲学家,1个任务用来按键读取,1个任务用来创建前面6个任务,创建完成后挂起自身。

注意:这里要创建5个信号量,需要OS_MAX_EVENTS不小于5,OS_MAX_EVENTS在

OS_CFG.h中更改。OS_TICKS_PER_SEC 为 200,也就是200个timetick为1秒

代码:

#include "includes.h"
#define  TASK_STK_SIZE   512 //任务堆栈长度
#define  TIME 50 //eat_time -> 60-TIME
OS_STK   StartTaskStk[TASK_STK_SIZE]; //定义任务堆栈区
OS_STK PhilosStk[5][TASK_STK_SIZE];
OS_STK ReadKeyStk[TASK_STK_SIZE];
INT8U PhilosID[]={1,2,3,4,5};
INT16S   key; //用于退出uCOS_II的键
INT16S   key1[] = {0x1B,0x31,0x32,0x33,0x34,0x35}; //检测输入
INT8U   err;
INT8U x=0, y=0; //字符显示位置
INT8U i=0;
BOOLEAN getKey;
OS_EVENT *ChopStick[5]; //声明5个信号量(筷子)
void  StartTask(void *data);
void  readKey(void *data);
void  Philos(void *data);
void  Eat(INT8U PhID);
void  Think(INT8U PhID);
/************************主函数*********************************************/
void  main (void)
{
char temp[50];
    OSInit(); //初始化uCOS_II
    PC_DOSSaveReturn(); //保存Dos环境
    PC_VectSet(uCOS, OSCtxSw); //安装uCOS_II中断
for(i=0;i<5;i++)
{
ChopStick[i]=OSSemCreate(1);
if (ChopStick[i]!=(OS_EVENT *)0) //创建无误则显示 无误
{
sprintf(temp,"ChopStick %d create no error",i);
PC_DispStr(40,19+i,temp,DISP_BGND_BLACK+DISP_FGND_YELLOW);
}
}
    OSTaskCreate(StartTask,0,&StartTaskStk[TASK_STK_SIZE - 1],4);
    OSStart();
}

//*****************************StartTask********************************************
void  StartTask(void *pdata)
{
// char temp[50];
pdata=pdata;
    OS_ENTER_CRITICAL();
    PC_VectSet(0x08, OSTickISR);
    PC_SetTickRate(OS_TICKS_PER_SEC);
    OS_EXIT_CRITICAL();
    OSStatInit();

OSTaskCreate(readKey, (void*)0, &ReadKeyStk[TASK_STK_SIZE - 1], 5);
for(i=0;i<5;i++)
{
err=OSTaskCreate(Philos,(void *)&PhilosID[i],&PhilosStk[i][TASK_STK_SIZE - 1],i+6);
// if(err==OS_NO_ERR)
// //test if task is created successfully
// {
// sprintf(temp,"Philosopher %d create no error %d",PhilosID[i],err);
// //OSTimeDly(200);
// PC_DispStr(40,0+i,temp,DISP_BGND_BLACK+DISP_FGND_PURPLE);
// }
}
OSTaskSuspend(OS_PRIO_SELF); //创建完成,挂起自己
}


//****************************readKey********************************************
void  readKey(void *pdata)
{
char *s = "Philosopher dining problem";
pdata=pdata;
for(; ;)
{

PC_DispStr(x,y,s,DISP_BGND_LIGHT_GRAY+DISP_FGND_RED);


PC_DispStr( 0, 24, "                            <-PRESS 'ESC' TO QUIT->                             ", DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY + DISP_BLINK);


getKey = PC_GetKey(&key);
if(key==key1[0]) //退出程序
{ PC_DOSReturn(); }
OSTimeDly(1);
}
}


//*****************************Philos********************************************
//the Philosopher first has to pick up the chopstick on his left hand then right
void  Philos(void *pdata)
{
INT32U  time;
INT8U   err1,err2;
INT8U PhID;
char temp[50];
PhID = *(INT8U *)pdata;
for(; ;)
{
if(key == key1[PhID]) //检测输入
{
sprintf(temp,"Philos %d apply for meal failed ",PhID);
PC_DispStr(x,PhID,temp,DISP_BGND_BLACK+DISP_FGND_RED);
time = OSTimeGet();                     //OS_TICKS_PER_SEC = 200
OSSemPend(ChopStick[(PhID-1)],1000,&err1);             //请求左右两根筷子
time = OSTimeGet() - time;                                     //第一个信号量等待时间,两个共5s + 1 TimeTick
OSSemPend(ChopStick[(PhID%5)],(1001-time),&err2);             //防止无限等待
if((err1 == OS_NO_ERR) && (err2 == OS_NO_ERR))                  //有两根,吃饭
{ Eat(PhID); }
else if((err1 == OS_NO_ERR) && (err2 == OS_TIMEOUT))
{ OSSemPost(ChopStick[(PhID-1)]); }                                 //一根,释放
else if((err2 == OS_NO_ERR) && (err1 == OS_TIMEOUT))
{ OSSemPost(ChopStick[(PhID%5)]); }                                 //一根,释放
else
{ Think(PhID); }                                                                 //其他,显示在思考
}
else                                 //没申请吃饭,显示在思考
{
Think(PhID);
OSTimeDly(1);
}
}
}


//*****************************Eat()***********************************************
void Eat(INT8U PhID) //显示吃饭并倒计时,吃完释放信号量
{
char temp[50];
INT8U j;
sprintf(temp,"Philos %d is eating     ",PhID);
PC_DispStr(x,PhID,temp,DISP_BGND_BLACK+DISP_FGND_GREEN);
for(j=TIME; j<60; j++)
{
if(j<60)
{
sprintf(temp,"countdown:  %d s ",60-j); //倒计时 60 - TIME
PC_DispStr(24,PhID,temp,DISP_BGND_BLACK+DISP_FGND_GREEN);
OSTimeDlyHMSM(0, 0, 1, 0);
}
if(j==59)
{
OS_ENTER_CRITICAL();
OSSemPost(ChopStick[(PhID%5)]); //吃完了,放回去
OSSemPost(ChopStick[(PhID-1)]);
OS_EXIT_CRITICAL();
OSTimeDly(1);
}
}
}


//*****************************Think()***********************************************
void Think(INT8U PhID) //显示思考
{
char temp[50];
sprintf(temp,"Philos %d is thinking                       ",PhID);
PC_DispStr(x,PhID,temp,DISP_BGND_BLACK+DISP_FGND_WHITE);
}

    信号量集

    实现起来相对于信号量要简单,就不多BB了

#include "includes.h"
#define  TASK_STK_SIZE   512 //任务堆栈长度
#define  TIME 50 //eat_time -> 60-TIME
OS_STK   StartTaskStk[TASK_STK_SIZE]; //定义任务堆栈区
OS_STK PhilosStk[5][TASK_STK_SIZE];
OS_STK ReadKeyStk[TASK_STK_SIZE];
INT8U PhilosID[] = {1,2,3,4,5};
INT8U Flag_Location[] = {0,3,6,12,24,17}; //每个需要的OS_FLAGS
INT16S   key; //用于退出uCOS_II的键
INT16S   key1[] = {0x1B,0x31,0x32,0x33,0x34,0x35}; //检测输入
INT8U   err;
INT8U x=0, y=0; //字符显示位置
INT8U i=0;
BOOLEAN getKey;
char *s1 = "Chop create no error";
OS_FLAG_GRP *Chop; //声明信号量集
void  StartTask(void *data);
void  readKey(void *data);
void  Philos(void *data);
void  Eat(INT8U PhID);
void  Think(INT8U PhID);
/************************主函数*********************************************/
void  main (void)
{
    OSInit(); //初始化uCOS_II
    PC_DOSSaveReturn(); //保存Dos环境
    PC_VectSet(uCOS, OSCtxSw); //安装uCOS_II中断


    Chop = OSFlagCreate(255, &err); //初始化信号量集
    if(err == OS_NO_ERR)
    { PC_DispStr(40,19,s1,DISP_BGND_BLACK+DISP_FGND_YELLOW); }
    OSTaskCreate(StartTask,0,&StartTaskStk[TASK_STK_SIZE - 1],4); //创建StartTask
    OSStart(); //启动多任务管理
}


//*****************************StartTask********************************************
void  StartTask(void *pdata)
{
// char temp[50];
pdata=pdata;
    OS_ENTER_CRITICAL();
    PC_VectSet(0x08, OSTickISR); //安装时钟中断向量
    PC_SetTickRate(OS_TICKS_PER_SEC); //设置时钟频率
    OS_EXIT_CRITICAL();
    OSStatInit();


for(i=0;i<5;i++) //创建5个任务
{
err=OSTaskCreate(Philos,(void *)&PhilosID[i],&PhilosStk[i][TASK_STK_SIZE - 1],10-i);
// if(err==OS_NO_ERR)
// //test if task is created successfully
// {
// sprintf(temp,"Philosopher %d create no error %d",PhilosID[i],err);
// //OSTimeDly(200);
// PC_DispStr(40,0+i,temp,DISP_BGND_BLACK+DISP_FGND_PURPLE);
// }
}
OSTaskCreate(readKey, (void*)0, &ReadKeyStk[TASK_STK_SIZE - 1], 5);
OSTaskSuspend(OS_PRIO_SELF);
}


//****************************readKey********************************************
void  readKey(void *pdata)
{
char *s = "Philosopher dining problem";
pdata=pdata;
for(; ;)
{
PC_DispStr(x,y,s,DISP_BGND_LIGHT_GRAY+DISP_FGND_RED);
PC_DispStr( 0, 24, "                            <-PRESS 'ESC' TO QUIT->                             ", DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY + DISP_BLINK);
getKey = PC_GetKey(&key);
if(key==key1[0]) //退出程序
{ PC_DOSReturn(); }
OSTimeDly(1);
}
}


//*****************************Philos********************************************
//the Philosopher first has to pick up the chopstick
void  Philos(void *pdata)
{
INT8U j;
INT8U PhID;
char temp[50];
PhID = *(INT8U *)pdata; //提取输入参数1 ~ 5
for(; ;)
{
if(key == key1[PhID]) //检测输入的是不是对应的,是则请求信号量集
{
sprintf(temp,"Philos %d apply for meal failed ",PhID); //OS_TICKS_PER_SEC = 200
PC_DispStr(x,PhID,temp,DISP_BGND_BLACK+DISP_FGND_RED); //请求time_out = 5s
OSFlagPend(Chop, (OS_FLAGS)Flag_Location[PhID], OS_FLAG_WAIT_SET_ALL+OS_FLAG_CONSUME, 1000, &err);
if(err == OS_NO_ERR) //请求成功则显示吃饭
{ Eat(PhID); }
else
{ Think(PhID); }
}
else //非对应则显示正在思考
{
Think(PhID);
OSTimeDly(1);
}
}
}


//*****************************Eat()***********************************************
void  Eat(INT8U PhID) //显示吃饭并倒计时,吃完释放信号量集
{
char temp[50];
INT8U j;
sprintf(temp,"Philos %d is eating     ",PhID);
PC_DispStr(x,PhID,temp,DISP_BGND_BLACK+DISP_FGND_GREEN);
for(j=TIME; j<60; j++)
{
if(j<60) //倒计时60 - TIME
{
sprintf(temp,"countdown:  %d s ",(60-j));
PC_DispStr(24,PhID,temp,DISP_BGND_BLACK+DISP_FGND_GREEN);
OSTimeDlyHMSM(0, 0, 1, 0);
}
if(j==59) //倒计时结束 -> 信号量集相应位置1
{
OSFlagPost(Chop, (OS_FLAGS)Flag_Location[PhID], OS_FLAG_SET, &err);
}
}
}


//*****************************Think()***********************************************
void Think(INT8U PhID) //显示思考
{
char temp[50];
sprintf(temp,"Philos %d is thinking                       ",PhID);
PC_DispStr(x,PhID,temp,DISP_BGND_BLACK+DISP_FGND_WHITE);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值