哲学家就餐问题
有5个哲学家,其生活方式是交替的进行思考和进餐。他们共用一张圆桌,分别坐在周围的5张椅子上,在圆桌上有五个碗和五支筷子,平时哲学家进行思考,饥饿时便试图取其左、右靠近他的筷子,只有在他拿到两支筷子时才能进餐。进餐毕,放下筷子继续思考,要求如下:
- 键盘上的按键0到1分别代表5个哲学家申请吃饭。
- 要求列出所有可能出现的状况,而且屏幕上必须将最新的状态显示出来。注:申请进餐未果维持5s后改为显示正在思考。
- 每位哲学家的进餐时间为20s(需要显示倒计时),进餐次数不做限定。
- 分别用全局变量(不用事件和信号量集标志组)、事件、信号量集标志组实现。
全局变量实现:
#include "INCLUDES.H"
#define TASK_SIZE_STK 512
#define TIME 40
OS_STK StartTaskStk[TASK_SIZE_STK];
OS_STK PhiTaskStk[5][TASK_SIZE_STK];
OS_STK KeyTaskStk[TASK_SIZE_STK];
INT8U x = 0, y = 0;
INT16S Key;
BOOLEAN KeyFlag;
INT8U PhiID[] = {1, 2, 3, 4, 5}; //哲学家编号
INT8U Stick[] = {1, 1, 1, 1, 1}; //全局变量,1代表筷子未被占用
INT16S KeyArray[] = {0x1B, 0x31, 0x32, 0x33, 0x34, 0x35};
//对应Esc,1,2,3,4,5按键
INT8U i;
void StartTask(void *pdata);
void PhiTask(void *pdata);
void KeyTask(void *pdata);
void Eat(INT8U x);
void Think(INT8U x);
void Fail(INT8U x);
void Reply(INT8U x);
void main()
{
OSInit();
PC_DOSSaveReturn();
PC_VectSet(uCOS, OSCtxSw);
OSTaskCreate(StartTask, (void *)0,
&StartTaskStk[TASK_SIZE_STK - 1], 0);
OSTaskCreate(KeyTask, (void *)0,
&KeyTaskStk[TASK_SIZE_STK - 1], 1);
OSStart();
}
void StartTask(void *pdata)
{
INT8U err;
char temp[50];
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR cpu_sr
#endif
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++)
{
err = OSTaskCreate(PhiTask, (void *)&PhiID[i],
&PhiTaskStk[i][TASK_SIZE_STK - 1], i + 2);
if(err == OS_NO_ERR)
{
sprintf(temp, "Task %d create successfully", i);
PC_DispStr(2, 20 + i, temp,
DISP_BGND_BLACK + DISP_FGND_WHITE);
}
}
//创建完成后挂起自己
OSTaskSuspend(OS_PRIO_SELF);
}
void KeyTask(void *pdata)
{
pdata = pdata;
for(;;)
{
KeyFlag = PC_GetKey(&Key);
if(Key == KeyArray[0])
{
PC_DOSReturn();
}
OSTimeDly(1);
}
}
void PhiTask(void *pdata)
{
//这里只能用局部变量,即为5个任务单独分配空间
INT8U ID;
char temp[50];
INT8U j;
INT32U time = 0;
pdata = pdata;
ID = *(INT8U *)pdata;
for(;;)
{
//读取到相应的按键
if(Key == KeyArray[ID])
{
for(j = 0; j < 5; j++)
{
if(Stick[ID - 1] == 1 && Stick[ID % 5] == 1)
{
Stick[ID - 1] = 0;
Stick[ID % 5] = 0;
j = 6;
Eat(ID);
}
else if(j < 4)
{
//显示申请
Reply(ID);
}
else if(j == 4)
{
//已经5s还不满足条件
Fail(ID);
}
else
{
Think(ID);
}
OSTimeDlyHMSM(0, 0, 1, 0);
}
OSTimeDly(1);
}
else
{
Think(ID);
OSTimeDly(1);
}
}
}
void Eat(INT8U ID)
{
INT8U j;
char temp[50];
sprintf(temp, "Philos %d is eating ", ID);
PC_DispStr(x, ID, temp,
DISP_BGND_BLACK + DISP_FGND_WHITE);
for(j = TIME; j < 60; j++)
{
if(j < 60)
{
//倒计时从60 - TIME开始
sprintf(temp, "countdown: %d s ", 60 - j);
PC_DispStr(24, ID, temp, DISP_BGND_BLACK + DISP_FGND_GREEN);
OSTimeDlyHMSM(0, 0, 1, 0);
}
if(j == 59)
{
Stick[ID - 1] = 1;
Stick[ID % 5] = 1;
OSTimeDly(1);
}
}
}
void Think(INT8U ID)
{
char temp[50];
sprintf(temp, "Philos %d is thinking ", ID);
PC_DispStr(x, ID, temp,
DISP_BGND_BLACK + DISP_FGND_WHITE);
}
void Fail(INT8U ID)
{
char temp[50];
sprintf(temp, "Philos %d apply for meal failed ", ID);
PC_DispStr(x, ID, temp, DISP_BGND_BLACK + DISP_FGND_RED);
}
void Reply(INT8U ID)
{
char temp[50];
sprintf(temp, "Philos %d is replying for meal ", ID);
PC_DispStr(x, ID, temp, DISP_BGND_BLACK + DISP_FGND_RED);
//申请的过程中如果也满足了条件,则同样跳转至Eat函数
if(Stick[ID - 1] == 1 && Stick[ID % 5] == 1)
{
Stick[ID - 1] = 0;
Stick[ID % 5] = 0;
Eat(ID);
}
}
事件实现:
#include "INCLUDES.H"
#define TASK_SIZE_STK 512
#define TIME 50
OS_STK StartTaskStk[TASK_SIZE_STK];
OS_STK PhiTaskStk[5][TASK_SIZE_STK];
OS_STK KeyTaskStk[TASK_SIZE_STK];
INT8U PhiID[] = {1, 2, 3, 4, 5};
INT8U x = 0, y = 0;
INT8U i;
INT16S Key;
BOOLEAN KeyFlag;
INT16S KeyArray[] = {0x1B, 0x31, 0x32, 0x33, 0x34, 0x35};
OS_EVENT *Semp[5]; //声明5个信号量
void StartTask(void *pdata);
void PhiTask(void *pdata);
void KeyTask(void *pdata);
void Eat(INT8U ID);
void Think(INT8U ID);
void Fail(INT8U ID);
void Reply(INT8U ID);
void main()
{
OSInit();
PC_DOSSaveReturn();
PC_VectSet(uCOS, OSCtxSw);
OSTaskCreate(StartTask, (void *)0,
&StartTaskStk[TASK_SIZE_STK - 1], 0);
OSTaskCreate(KeyTask, (void *)0,
&KeyTaskStk[TASK_SIZE_STK - 1], 1);
OSStart();
}
void StartTask(void *pdata)
{
INT8U err;
char temp[50];
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR cpu_sr
#endif
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++)
{
err = OSTaskCreate(PhiTask, (void *)&PhiID[i],
&PhiTaskStk[i][TASK_SIZE_STK - 1], i + 2);
if(err == OS_NO_ERR)
{
sprintf(temp, "Task %d Creats Successfully", i);
PC_DispStr(2, 20 + i, temp,
DISP_FGND_WHITE + DISP_BGND_BLACK);
}
//定义5个信号量,初值为1
Semp[i] = OSSemCreate(1);
if(Semp[i] != (OS_EVENT *)0)
{
sprintf(temp, "Semphore %d Creates Successfully", i);
PC_DispStr(40, 20 + i, temp,
DISP_BGND_BLACK + DISP_FGND_WHITE);
}
}
OSTaskSuspend(OS_PRIO_SELF);
}
void KeyTask(void *pdata)
{
pdata = pdata;
for(;;)
{
KeyFlag = PC_GetKey(&Key);
if(Key == KeyArray[0])
{
PC_DOSReturn();
}
OSTimeDly(1);
}
}
void PhiTask(void *pdata)
{
char temp[50];
INT8U err1, err2;
INT32U time;
INT8U ID;
pdata = pdata;
ID = *(INT8U *)pdata;
for(;;)
{
if(Key == KeyArray[ID])
{
sprintf(temp, "Philos %d is applying for meal ", ID);
PC_DispStr(x, ID, temp, DISP_BGND_BLACK + DISP_FGND_RED);
time = OSTimeGet();
OSSemPend(Semp[ID - 1], 1000, &err1);
time = OSTimeGet() - time;
OSSemPend(Semp[ID % 5], 1001 - time, &err2);
if(err1 == OS_NO_ERR && err2 == OS_NO_ERR)
{
//都申请成功,直接跳转到Eat函数
Eat(ID);
}
else if(err1 == OS_NO_ERR && err2 == OS_TIMEOUT)
{
OSSemPost(Semp[ID - 1]);
Fail(ID);
}
else if(err1 == OS_TIMEOUT && err2 == OS_NO_ERR)
{
OSSemPost(Semp[ID % 5]);
Fail(ID);
}
else
{
Think(ID);
}
OSTimeDly(1);
}
else
{
Think(ID);
OSTimeDly(1);
}
}
}
void Eat(INT8U ID)
{
char temp[50];
INT8U j;
sprintf(temp, "Philos %d is eating ", ID);
PC_DispStr(x, ID, temp,
DISP_FGND_WHITE + DISP_BGND_BLACK);
for(j = TIME; j < 60; j++)
{
if(j <= 59)
{
sprintf(temp, "last time: %d ", 60 - j);
PC_DispStr(24, ID, temp,
DISP_FGND_WHITE + DISP_BGND_BLACK);
OSTimeDlyHMSM(0, 0, 1, 0);
}
if(j == 59)
{
OSSemPost(Semp[ID - 1]);
OSSemPost(Semp[ID % 5]);
OSTimeDly(1);
}
}
}
void Think(INT8U ID)
{
char temp[50];
sprintf(temp, "Philos %d is thinking ", ID);
PC_DispStr(x, ID, temp,
DISP_BGND_BLACK + DISP_FGND_WHITE);
}
void Fail(INT8U ID)
{
char temp[50];
sprintf(temp, "Philos %d reply for meal failed ", ID);
for(i = 0; i < 2; i++)
{
PC_DispStr(x, ID, temp,
DISP_BGND_BLACK + DISP_FGND_WHITE);
OSTimeDlyHMSM(0, 0, 0, 400);
}
}
void Reply(INT8U ID)
{
char temp[50];
sprintf(temp, "Philos %d is thinking ", ID);
PC_DispStr(x, ID, temp,
DISP_BGND_BLACK + DISP_FGND_WHITE);
}
信号量集标志组实现:
#include "INCLUDES.H"
#define TASK_SIZE_STK 512
#define TIME 50
OS_STK StartTaskStk[TASK_SIZE_STK];
OS_STK PhiTaskStk[5][TASK_SIZE_STK];
OS_STK KeyTaskStk[TASK_SIZE_STK];
INT8U PhiID[] = {1, 2, 3, 4, 5};
INT8U x = 0, y = 0;
INT8U i;
INT16S Key;
BOOLEAN KeyFlag;
INT16S KeyArray[] = {0x1B, 0x31, 0x32, 0x33, 0x34, 0x35};
//声明信号量集,只需要1个即可
OS_FLAG_GRP *Semp_F;
INT8U Flag_Location[] = {0, 3, 6, 12, 24, 17};
void StartTask(void *pdata);
void PhiTask(void *pdata);
void KeyTask(void *pdata);
void Eat(INT8U ID);
void Think(INT8U ID);
void Fail(INT8U ID);
void Reply(INT8U ID);
void main()
{
OSInit();
PC_DOSSaveReturn();
PC_VectSet(uCOS, OSCtxSw);
OSTaskCreate(StartTask, (void *)0,
&StartTaskStk[TASK_SIZE_STK - 1], 0);
OSTaskCreate(KeyTask, (void *)0,
&KeyTaskStk[TASK_SIZE_STK - 1], 1);
OSStart();
}
void StartTask(void *pdata)
{
INT8U err;
char temp[50];
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR cpu_sr
#endif
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++)
{
err = OSTaskCreate(PhiTask, (void *)&PhiID[i],
&PhiTaskStk[i][TASK_SIZE_STK - 1], i + 2);
if(err == OS_NO_ERR)
{
sprintf(temp, "Task %d Creats Successfully", i);
PC_DispStr(2, 20 + i, temp,
DISP_FGND_WHITE + DISP_BGND_BLACK);
}
}
Semp_F = OSFlagCreate(255, &err);
if(err == OS_NO_ERR)
{
sprintf(temp, "OS_FLAG Creats Successfully");
PC_DispStr(40, 20, temp,
DISP_FGND_WHITE + DISP_BGND_BLACK);
}
OSTaskSuspend(OS_PRIO_SELF);
}
void KeyTask(void *pdata)
{
pdata = pdata;
for(;;)
{
KeyFlag = PC_GetKey(&Key);
if(Key == KeyArray[0])
{
PC_DOSReturn();
}
OSTimeDly(1);
}
}
void PhiTask(void *pdata)
{
char temp[50];
INT8U errPhi;
INT8U ID;
pdata = pdata;
ID = *(INT8U *)pdata;
for(;;)
{
if(Key == KeyArray[ID])
{
sprintf(temp, "Philos %d is applying for meal ", ID);
PC_DispStr(x, ID, temp, DISP_BGND_BLACK + DISP_FGND_RED);
OSFlagPend(Semp_F,
(OS_FLAGS)Flag_Location[ID],
OS_FLAG_WAIT_SET_ALL + OS_FLAG_CONSUME,
1000, &errPhi
);
if(errPhi == OS_NO_ERR)
{
Eat(ID);
}
else
{
Fail(ID);
}
}
else
{
Think(ID);
OSTimeDly(1);
}
}
}
void Eat(INT8U ID)
{
char temp[50];
INT8U j;
INT8U err;
sprintf(temp, "Philos %d is eating ", ID);
PC_DispStr(x, ID, temp,
DISP_FGND_WHITE + DISP_BGND_BLACK);
for(j = TIME; j < 60; j++)
{
if(j <= 59)
{
sprintf(temp, "last time: %d ", 60 - j);
PC_DispStr(24, ID, temp,
DISP_FGND_WHITE + DISP_BGND_BLACK);
OSTimeDlyHMSM(0, 0, 1, 0);
}
if(j == 59)
{
OSFlagPost(Semp_F, (OS_FLAGS)Flag_Location[ID], OS_FLAG_SET, &err);
OSTimeDly(1);
}
}
}
void Think(INT8U ID)
{
char temp[50];
sprintf(temp, "Philos %d is thinking ", ID);
PC_DispStr(x, ID, temp,
DISP_BGND_BLACK + DISP_FGND_WHITE);
}
void Fail(INT8U ID)
{
char temp[50];
sprintf(temp, "Philos %d reply for meal failed ", ID);
for(i = 0; i < 2; i++)
{
PC_DispStr(x, ID, temp,
DISP_BGND_BLACK + DISP_FGND_WHITE);
OSTimeDlyHMSM(0, 0, 0, 400);
}
}
void Reply(INT8U ID)
{
char temp[50];
sprintf(temp, "Philos %d is thinking ", ID);
PC_DispStr(x, ID, temp,
DISP_BGND_BLACK + DISP_FGND_WHITE);
}