互斥型信号量

来源:互联网 发布:sql安装参数错误 编辑:程序博客网 时间:2024/05/24 01:28

在任哲的书本《嵌入式实时操作系统uc/osII原理与应用》第五章所描述的,互斥型信号量将占用共享资源的任务提升到当前最高的优先级,使其能够完整的执行完毕,然后再恢复原先的优先级;这样避免了仅仅使用信号量而出现优先级反转的现象,(当然互斥型信号量就是出于这个目的设计的吧)。
所以在书里的程序里面设计了这样三个任务。优先级为6的任务MyTask、优先级为7的任务YouTask,和优先级为8的HerTask。
HerTask一开始占用了优先级为3的互斥信号量Semp,并且占用时间比较长。

/*****利用互斥信号量消除了优先级反转的现象**************/#include "includes.h"#define  TASK_STK_SIZE   512            //任务堆栈长度OS_STK   MyTaskStk[TASK_STK_SIZE];  //定义任务堆栈区OS_STK   YouTaskStk[TASK_STK_SIZE]; //定义任务堆栈区OS_STK   HerTaskStk[TASK_STK_SIZE]; //定义任务堆栈区OS_STK   StartTaskStk[TASK_STK_SIZE];//char *s1="MyTask running";char *s2="YouTask running";char *s3="HerTask running";char *ss="MyTask pend_semp";INT8U err;INT8U y=0;INT32U Times=0;INT16S   key;                           //用于退出uCOS_II的键OS_EVENT *Semp;                //声明事件控制块void  MyTask(void *pdata);                  //声明任务void  YouTask(void *pdata);                 //声明任务void  HerTask(void *pdata);                 //声明任务void StartTask(void *pdata);void QuitKey(void);/***************主函数*****************/void  main (void){     OSInit();                              //初始化uCOS_II     PC_DOSSaveReturn( );               //保存Dos环境     PC_VectSet(uCOS, OSCtxSw);     //安装uCOS_II中断     Semp=OSMutexCreate(3,&err);       //定义信号量     OSTaskCreate(StartTask,            //创建任务MyTask        (void*)0,                           //给任务传递参数        &StartTaskStk[TASK_STK_SIZE - 1],   //设置任务堆栈栈顶指针        5);                             //使任务的优先级别为5     OSStart();                         //启动多任务管理}/*************任务StartTask***************/void  StartTask (void *pdata){     pdata = pdata;     OS_ENTER_CRITICAL();     PC_VectSet(0x08, OSTickISR);           //安装时钟中断向量     PC_SetTickRate(OS_TICKS_PER_SEC);  //设置uCOS_II时钟频率     OS_EXIT_CRITICAL();     OSStatInit( );                         //初始化统计任务     OSTaskCreate(MyTask,                   //创建任务YouTask            0,                          //给任务传递参数        &MyTaskStk[TASK_STK_SIZE - 1],  //设置任务堆栈栈顶指针        6);                         //使任务的优先级别为6     OSTaskCreate(YouTask,                  //创建任务YouTask            0,                          //给任务传递参数        &YouTaskStk[TASK_STK_SIZE - 1], //设置任务堆栈栈顶指针        7);                         //使任务的优先级别为7        OSTaskCreate(HerTask,                   //创建任务YouTask            0,                          //给任务传递参数        &HerTaskStk[TASK_STK_SIZE - 1], //设置任务堆栈栈顶指针        8);        OSTaskSuspend(OS_PRIO_SELF);  //把StartTask给挂起来了}/******任务MyTask**********/void  MyTask (void *pdata){     pdata = pdata;     for (;;)     {        OSTimeDlyHMSM(0,0,0,200);        {        PC_DispStr(10,++y,ss,DISP_BGND_BLACK+DISP_FGND_WHITE);        OSMutexPend(Semp,0,&err);       PC_DispStr(10,++y,s1,DISP_BGND_BLACK+DISP_FGND_WHITE);        OSMutexPost(Semp);//发送信号量        QuitKey();        }        OSTimeDlyHMSM(0,0,0,200);      }}/************任务YouTask*************/void  YouTask (void *pdata){     pdata = pdata;     for (;;)     {        PC_DispStr(10,++y,s2,DISP_BGND_BLACK+DISP_FGND_WHITE);        QuitKey();        OSTimeDlyHMSM(0,0,0,300);   //等待300ms     }}/************任务HerTaskk*******************/void  HerTask (void *pdata){    pdata = pdata;     for (;;)     {        OSMutexPend(Semp,0,&err);//请求信号量                PC_DispStr(10,++y,s3,DISP_BGND_BLACK+DISP_FGND_WHITE);//显示s3,表示请求成功        for(Times=0;Times<40000000;Times++)            {OS_Sched();}        OSMutexPost(Semp);//占用较长的时间,这里才释放互斥型信号量        QuitKey();        OSTimeDlyHMSM(0,0,1,0);        }}/*******************按键退出************************/void    QuitKey(void){    //如果按下Esc键则退出uCOS_II        if (PC_GetKey(&key) == TRUE)        {                if (key == 0x1B)            {                     PC_DOSReturn( );//恢复DOS环境            }        }}

运行结果:
这里写图片描述

看运行结果,先出现MyTask后出现YouTask ,正如我们所期望的,消除了优先级反转。

但是,出于好奇,我在HerTask任务里面加了一句。如下面代码所示。

for (;;)     {        OSMutexPend(Semp,0,&err);                      PC_DispStr(10,++y,s3        ,DISP_BGND_BLACK+DISP_FGND_WHITE);        for(Times=0;Times<40000000;Times++)            {OS_Sched();}        OSMutexPost(Semp);//加了下面这一句,通过显示HerTask over来确认HerTask什么时候释放了信号量    PC_DispStr(10,++y,"HerTask over",        DISP_BGND_BLACK+DISP_FGND_WHITE);        QuitKey();        OSTimeDlyHMSM(0,0,1,0);        }

而运行结果让我惊讶。
这里写图片描述

乍一看,怎么HerTask没有释放信号量,MyTask就已经得到互斥信号量并且运行了呢,YouTask也运行了。这不是和理论相违背吗。按照常理,不是应该HerTask先释放信号量,然后MyTask才能请求,运行吗?
先别忙着质疑理论,为了弄清楚哪里出错了,我又在HerTask释放信号量的语句前,加了一句显示的语句,

for (;;)     {        OSMutexPend(Semp,0,&err);       PC_DispStr(10,++y,s3,DISP_BGND_BLACK+DISP_FGND_WHITE);        for(Times=0;Times<40000000;Times++)            {OS_Sched();}        //这一次在释放前加了一句显示HerTask over1        PC_DispStr(10,++y,"HerTask over1",        DISP_BGND_BLACK+DISP_FGND_WHITE);        OSMutexPost(Semp);        PC_DispStr(10,++y,"HerTask over",        DISP_BGND_BLACK+DISP_FGND_WHITE);        QuitKey();        OSTimeDlyHMSM(0,0,1,0);        }

结果如下:
这里写图片描述
说明MyTask获得信号量是在HerTask任务的语句:for(Times=0;Times<40000000;Times++){OS_Sched();}之后才获得信号量的,准确来说是在显示了字符串”HerTask over1”之后才获得信号量的。
所以,只能说明在显示完”HerTask over1”之后,任务进行了切换,而且切换发生在了显示”HerTask over”之前,那么也就是说在OSMutexPost()函数里面肯定进行了切换。这是唯一的可能了,因为没有设置中断切换,那么要从HerTask转到MyTask执行,就只剩下任务级切换了。所以我查了一下OSMutexPost()函数的定义,发现函数里面确实调用了OSched()进行了任务的切换,所以说此次切换就是使得MyTask得以执行。所以以上的疑问也就解开了。
以上就是我对于互斥型信号量的一些理解,不妥之处欢迎指正。

0 0
原创粉丝点击