uCOS II的ucosiii 信号量量及任务优先级问题求助

关于uCOS-II中优先级翻转问题_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
关于uCOS-II中优先级翻转问题
上传于||文档简介
&&μ​C​o​s​_​I​I
阅读已结束,如果下载本文需要使用0下载券
想免费下载更多文档?
定制HR最喜欢的简历
你可能喜欢2218人阅读
uC/OS-II(5)
一. 任务优先级反转的概念
当任务以独占方式使用共享资源时,会出出低优先级任务先于高优先级任务而被运行的现象,这就是所谓的任务优先级反转。
1. 任务A和任务C都要使用同一共享资源S,现在假设任务A和任务B都在等待与各自任务相关的事件发生而处于等待状态,而任务C正在运行,且在t1时刻取得了信号量的并开始访问共享资源S。
2. 如果在任务C使用共享资源S过程中的t2时刻,任务A等待的事件到来,那么由于任务A的优先级别高于任务C,所以任务A就剥夺C的CPU而进入运行状态,而使任务C中止运行,这样C就失去了释放信号量的机会。
3. 如果任务A在运行中的t3时刻也要访问共享资源S,但是由于任务C还未释放信号量,因此任务A只好等待。
4. 上面三步出没什么问题,但是如果在任务C继续使用共享资源S过程中的t4时刻,任务B所等待的事件也来临了,由于任务B的优先级也高于任务C,任务B当然要剥夺任务C的CPU而进入运行状态,任务C则只好等待。
5. 同样,任务A也只有等待B运行结束,并且任务C释放信号量的t6时刻才能运行。
综上所述,低优先级任务B反而先于高优先级的任务A运行,这种现象叫做任务优先级的反转。
用代码表示如下:
//优先级 MyTask & YouTask & HerTask
MyTask(void *pdata)
OSTimeDlyHMSM(0,0,0,200); /* 等待200ms */
OSSemPend(Fun_Semp, 0, &err); /*request signal */
/* Do something */
OSSemPost(Fun_Semp); /* send signal */
OSTimeDlyHMSM(0,0,0,200); /* 等待200ms */
YouTask(void *pdata)
/* Do something */
OSTimeDlyHMSM(0,0,0,300); /* 等待300ms */
HerTask(void *pdata)
OSSemPend(Fun_Semp, 0, &err); /*request signal */
for(T Times&;Times++)
/* Do something */
OS_Sched();
OSSemPost(Fun_Semp); /* send signal */
OSTimeDlyHMSM(0,0,1,0); /* 等待1s */
运行结果如下:
二. 互斥信号量
从上面的例子发现:
使用信号量的任务是否能够运行,受到任务的优先级别以及是否占用信号量两个条件约束,而信号量的约束高于优先级别的约束。
于是,当出现低优先级别的任务与高优先级别的任务使用同一个信号量,而系统中还存在其他中等优先级别的任务时,如果低优先级别的任务先获得了信号量,就会使高优先级别的任务处于等待状态,而那些不使用该信号的中等待优先级别的任务却可以剥夺低优先级别任务的CPU使用权而先于高优先级别的任务而运行了。
解决问题的办法之一是:
使获得信号任务的优先级别在使用共享资源期间暂时提升到所有任务最高优先级的高一个级别上(最高优先级+1),以使该任务不被其他任务所打断,从而能尽快地使用完共享资源并释放信号量,然后在释放信号量之后,再恢复该任务原来的优先级别。
互斥信号量:
互斥信号量就是按上面的解决办法设计的,在描述互斥信号量的事件控制块中,除成员OSEventType=OS_EVENT_TYPE_MUTEX以表明这是一个互斥信号量,成员OSEventCnt被分成了低8位和高8位两部分;
低8位用来存放信号值(0xff时信号有效,即信号量尚未被任何任务所占用;否则信号为无效);
高8位用来存放为了避免出现优先级反转现象而要提升的优先级别。
相关操作:
1. 创建互斥型信号量
//参数prio表明要提升的优先级别
*OSMutexCreate (INT8U prio, INT8U *err);2. 请求互斥型信号量
OSMutexPend (OS_EVENT *pevent, INT16U timeout, INT8U *err);3. 发送互斥型信号量
OSMutexPost (OS_EVENT *pevent);4. 获取互斥型信号量的当前状态
OSMutexQuery (OS_EVENT *pevent, OS_MUTEX_DATA *pdata);5. 删除互斥型信号量
*OSMutexDel (OS_EVENT *pevent, INT8U opt, INT8U *err);
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:530164次
积分:6029
积分:6029
排名:第2804名
原创:191篇
转载:29篇
评论:268条
文章:16篇
阅读:24066
(1)(12)(1)(1)(1)(3)(8)(3)(4)(8)(1)(1)(7)(2)(11)(1)(8)(5)(10)(26)(11)(26)(11)(3)(1)(1)(6)(2)(3)(7)(1)(5)(2)(5)(1)(1)(5)(6)(1)(7)(3)查看: 1290|回复: 17
uCOS II的信号量及任务优先级问题求助。
主题帖子精华
中级会员, 积分 407, 距离下一级还需 93 积分
在线时间46 小时
我用ucos建立了2个任务,任务1的优先级为2,任务2的优先级为3.
新建了一个信号量,初始值为1.
哪位能给你解惑一下:
1、任务1输出3,信号量发出后,为什么任务2没有执行呢?而是任务1把4和0输出,且把自己挂起后才执行任务2呢?
2、任务1把自己挂起时,那时信号量为1,他的优先级比任务2的高(任务2已经就绪,任务1也就绪了呀),应该是任务1继续
& & 执行的,为什么任务2却执行了?
下面是串口输出的语句:下面3行特意做了换行,原本这里是没有换行的。
[C] 纯文本查看 复制代码/*****************************任务1*****************************************/
Task1 (void *p_arg)
printf(\"0\");
OSSemPend( sem, 0, &err );
printf(\"1\");
printf(\"2\");
OSTimeDlyHMSM(0,0,0,100);
printf(\"3\");
OSSemPost( sem );
printf(\"4\");
/********************************任务2**************************************/
Task2 (void *p_arg)
printf(\"5\");
OSSemPend( sem, 0, &err );
printf(\"6\");
printf(\"7\");
OSTimeDlyHMSM(0,0,1,0);
printf(\"8\");
OSSemPost( sem );
printf(\"9\");
2、UCOS在第一次初始化完成并开启以后,所有的任务就会都进入就绪态。
3、此时task1开始运行,首先输出“0”,由于sem初始为1。因此task1请求信号量成功,接着输出“1”、"2"。然后运行OSTimeDlayHMSM()函数对task1进行延时并发起任务调度,task1进入等待态,task2开始运行。
4、task2开始运行,输出"5"以后请求信号量sem,但是此时由于task1请求过一次sem了,此时sem为0,而且task2中请求sem采用的“死等”的方式,超时时间为0, ...
主题帖子精华
在线时间351 小时
2、UCOS在第一次初始化完成并开启以后,所有的任务就会都进入就绪态。
3、此时task1开始运行,首先输出“0”,由于sem初始为1。因此task1请求信号量成功,接着输出“1”、"2"。然后运行OSTimeDlayHMSM()函数对task1进行延时并发起任务调度,task1进入等待态,task2开始运行。
4、task2开始运行,输出"5"以后请求信号量sem,但是此时由于task1请求过一次sem了,此时sem为0,而且task2中请求sem采用的“死等”的方式,超时时间为0,因此此时任务切换,切换到就绪了的最高任务,延时100ms以后,task1也就绪了,那么此时task1开始运行了。
5、task1从上次被中断的地方接着运行,输出“3”,然后OSemPost()函数运行,释放sem。函数OSSemPost()在对信号量的计数器操作之前首先检查是否还有等待该信号量的任务,如果没有的话就将信号量计数器OSEventCnt加1,如果有的话,将此任务加入就绪表中,然后调用OSSched()函数去运行等待任务中优先级别最高的任务。上面说过了task2正在傻傻的“死等"sem能够回心转意,而且此时只有task2一个在等待sem,因此sem也选择了task2的怀抱,task2重新开始运行。一切看如此的合乎情理,但是世事难料啊!task2要想和sem在一起谈何容易啊!城南小陌又逢春,只见梅花不见人!!!究其原因就是OSSchend()函数做切换的时候会首先判断当前正在运行的任务是否是最高优先级的任务,我们知道task1优先级比task2高,因此,task2暂时不能运行啊!而task1接着运行!!伤心的人儿在等待,何日再与君相见,共剪西窗烛,共话巴山夜雨!
6、task1接着运行,输出”4“、”0“。然后调用OSSemPend()函数请求信号量,但是此时sem为0,额额额?为什么sem为0?不是task1调用了一次OSSemPost()释放了sem的吗?请注意!我们前面说过,如果有任务请求sem的话,OSSemPost()函数会直接运行等待任务中优先级最高的那个,就不会将sem的计数器加1了,因此此处的sem为0!!这点很重要请注意查看OSSemPost()函数的源码!task1由于请求不到sem,不得不放弃CPU使用权,发起任务调度,此时task2才接着从在很久之前被中断的地方接着运行!
6、task2开始从上次被中断的地方接着运行,输出”6“,”7“。
7、以后发生的事情楼主自己去分析吧,我只能帮到这里了!注意一定要看OSSemPend()、OSSemPost()和OSSched()这三个函数的源码,仔细认真的分析!
开往春天的手扶拖拉机
主题帖子精华
在线时间310 小时
1,因为任务&1的优先级高.
2,任务2既然挂起了,那就不会就绪.
我是开源电子网站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺:
微信公众平台:正点原子
主题帖子精华
中级会员, 积分 407, 距离下一级还需 93 积分
在线时间46 小时
回复【2楼】正点原子:
-----------------------------
原子哥,关于第二个问题我还是不明白。
按照你的说法,那么可以这么推断:
上电后程序执行到任务1,把0输出挂起自己,这是任务1就到等待里去了,此时任务2执行,输出5,挂起自己。
但是实际上输出的是012···,不是05···
这个如何解释?
任务1把自己挂起时信号量是有效的,所以就应该继续执行任务1的,怎么又跑到任务2了呢?
这个执行顺序怎么和刚上电时的逻辑不一样呢?
主题帖子精华
初级会员, 积分 119, 距离下一级还需 81 积分
在线时间7 小时
任务2输出5之后,由于等待信号量被挂起,之后任务1输出3,然后发信号量,注意发信号亮并不是简单的+1,OSSemPost中有这几行代码
if&(pevent-&OSEventGrp&!=&0)&{
&&&&&&&&(void)OS_EventTaskRdy(pevent,&(void&*)0,&OS_STAT_SEM,&OS_STAT_PEND_OK);
&&&&&&&&OS_EXIT_CRITICAL();
&&&&&&&&OS_Sched();
&&&&&&&&return&(OS_ERR_NONE);
&&&&}
此时因为任务2的优先级较1低,所以没有立即运行,而是任务1继续输出4、0然后挂起自己,任务2就运行了,输出678
主题帖子精华
中级会员, 积分 407, 距离下一级还需 93 积分
在线时间46 小时
回复【4楼】holy:
---------------------------------
谢谢回答,还是没有理解这里:任务1继续输出4、0然后挂起自己。挂起自己时信号量是有效的,为什么任务1没有继续执行呢???
而是去执行任务2了。
情形1:任务2输出8后发送信号量,此时任务1正在挂起,任务2发出信号量后为什么这次任务1马上就去执行了?
情形2:任务1输出3后发送一个信号量,输出4、0,然后挂起自己(其实是要等待一个信号量),但是任务1在输出3后就发送了一个信号量了,为什么此时任务1没有使用这个信号量呢?&为什么在情形1中任务2发送信号量后任务1就立马运行了(这个情况我理解:任务1的优先级高,所以抢先执行了;那为什么任务1自己发送的信号量,自己挂起时没有使用自己发送的信号量呢?这个是不是和情形2矛盾了????)。
主题帖子精华
初级会员, 积分 119, 距离下一级还需 81 积分
在线时间7 小时
回复【5楼】天山狐狸:
---------------------------------
我说的还不够清楚吗?
主题帖子精华
在线时间310 小时
楼主直接单步跟踪代码去分析下吧.
我是开源电子网站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺:
微信公众平台:正点原子
主题帖子精华
中级会员, 积分 407, 距离下一级还需 93 积分
在线时间46 小时
回复【6楼】holy:
---------------------------------
不是很清楚,就那一点没有讲清楚
主题帖子精华
中级会员, 积分 407, 距离下一级还需 93 积分
在线时间46 小时
回复【7楼】正点原子:
---------------------------------
好吧,我试试
主题帖子精华
中级会员, 积分 407, 距离下一级还需 93 积分
在线时间46 小时
回复【10楼】zuozhongkai:
---------------------------------
谢谢ls,分析的十分清晰、幽默,语文水平很高啊。我终于明白那个地方了,原来第一次OSSemPost后sem没有加1,理解这一点所有的都理解了。再次感谢。
***************************************分割线******************************************
关于第4条我还有点疑惑,你看看我理解的对吗
你的原文如下
4、task2开始运行,输出&5&以后请求信号量sem,但是此时由于task1请求过一次sem了,此时sem为0,而且task2中请求sem采用的“死等”的方式,超时时间为0,因此此时任务切换,切换到就绪了的最高任务,延时100ms以后,task1也就绪了,那么此时task1开始运行了。
我的理解:
从“超时时间为0”&&开始,我的理解是:此时任务做了切换,但切换到了空闲任务中。【在任务1调用OSTimeDlyHMSM()后就已经开始100ms计时了,并做了任务切换,即从任务1切换到了任务2。】,程序一直在空闲任务中运行,知直到100ms到了后才从空闲任务切换到了就绪到的任务1,任务1开始运行。
下面是OSTimeDly的源码,先把ticks放到OSTCBDly&中,后才做的任务切换。
void&&OSTimeDly&(INT32U&ticks)
{
&&&&INT8U&&&&&&y;
#if&OS_CRITICAL_METHOD&==&3u&&&&&&&&&&&&&&&&&&&&&/*&Allocate&storage&for&CPU&status&register&&&&&&&&&&&*/
&&&&OS_CPU_SR&&cpu_sr&=&0u;
#endif
&&&&if&(OSIntNesting&&&0u)&{&&&&&&&&&&&&&&&&&&&&&/*&See&if&trying&to&call&from&an&ISR&&&&&&&&&&&&&&&&&&*/
&&&&&&&&
&&&&}
&&&&if&(OSLockNesting&&&0u)&{&&&&&&&&&&&&&&&&&&&&/*&See&if&called&with&scheduler&locked&&&&&&&&&&&&&&&&*/
&&&&&&&&
&&&&}
&&&&if&(ticks&&&0u)&{&&&&&&&&&&&&&&&&&&&&&&&&&&&&/*&0&means&no&delay!&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
&&&&&&&&OS_ENTER_CRITICAL();
&&&&&&&&y&&&&&&&&&&&&=&&OSTCBCur-&OSTCBY;&&&&&&&&/*&Delay&current&task&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
&&&&&&&&OSRdyTbl[y]&&=&(OS_PRIO)~OSTCBCur-&OSTCBBitX;
&&&&&&&&if&(OSRdyTbl[y]&==&0u)&{
&&&&&&&&&&&&OSRdyGrp&&=&(OS_PRIO)~OSTCBCur-&OSTCBBitY;
&&&&&&&&}
&&&&&&&&OSTCBCur-&OSTCBDly&=&&&&&&&&&&&&&&&/*&Load&ticks&in&TCB&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
&&&&&&&&OS_EXIT_CRITICAL();
&&&&&&&&OS_Sched();&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&/*&Find&next&task&to&run!&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
&&&&}
}
主题帖子精华
在线时间351 小时
回复【11楼】天山狐狸:
---------------------------------
有切换到空闲任务的可能,如果task1的延时还没结束,那么肯定会切换到空闲任务的。
开往春天的手扶拖拉机
主题帖子精华
中级会员, 积分 407, 距离下一级还需 93 积分
在线时间46 小时
回复【12楼】zuozhongkai:
---------------------------------
如果切换到空闲任务的话
我上面的理解对吗?
主题帖子精华
在线时间351 小时
回复【13楼】天山狐狸:
---------------------------------
嗯,是的,你要知道一点的是OSSched()函数永远是在找就绪表中已经就绪了的最高优先级的那个任务运行的。此时task1的优先级最高,而且已经就绪了,那么做任务切换的时候肯定会切换到task1的
开往春天的手扶拖拉机
主题帖子精华
中级会员, 积分 407, 距离下一级还需 93 积分
在线时间46 小时
回复【14楼】zuozhongkai:
---------------------------------
嗯,完全理解了
主题帖子精华
初级会员, 积分 119, 距离下一级还需 81 积分
在线时间2 小时
回复【10楼】zuozhongkai:
---------------------------------
楼主&假如运行任务2&是不是执行到任务2的ossempend()还要等待
主题帖子精华
初级会员, 积分 119, 距离下一级还需 81 积分
在线时间2 小时
回复【10楼】zuozhongkai:
---------------------------------
任务2等于是没有等到sem&是吧
主题帖子精华
在线时间351 小时
回复【17楼】wenwu1109:
---------------------------------
运行到ossempend()函数肯定要等待指定地的信号量,如果函数超时参数设置为0就一直等待,如果不为0的话就等待指定的时间。
开往春天的手扶拖拉机
Powered by5084人阅读
嵌入式(12)
操作系统(8)
一:UCOS是一种抢占式的多任务操作系统,如果最高优先级的任务不主动放弃CPU的使用的话,其他任务是无法运行的,通常情况下,高优先级的任务在使用完CPU或其他资源后都要主动放弃,可以通过延时函数或者时等待一些信号量之类的让自己挂起。但是如果最高优先级任务一直使用CPU,那就跟单任务没有什么区别了。
二:可以通过等待信号量,消息等是当前任务挂起,或者通过通过延时函数将任务挂起,从而让其他优先级的任务运行。
UC/OS的信号量,消息队列,邮箱的区别
& & 信号量像一把钥匙,任务要运行下去,需先拿到这把钥匙。
& & 消息邮箱是一个指针型变量。可以向一个任务或一个中断服务子程序发送一则消息(一个指针),同样,一个或多个任务通过内核服务,可以接收这则消息。消息邮箱也可以当作只取2个值的信号量来用。
& & 消息队列实际上是邮箱阵列。
& & 看了《嵌入式实时操作系统uC/OS-II》也快一个星期了,期间断断续续的边工作边看,依照书的目录,大致细分了系统各个功能:任务管理,时间管理,事件控制,信号量管理,互斥型信号量管理,事件标志组管理,信息邮箱管理,信息队列管理,内存管理等,这个次序也是以后要逐个理解学习的次序。
& &&现在下了个移植到51的源代码,学习任务管理部分,试尝编写了个任务程序,为了把能够用上的函数使用上,程序就显得有点臃肿,程序我保证是能够通过编译并且无错误的。
& & &程序粘贴上去 dat=&dat总是变成dat&=&dat&,多了个&&,如果大家要用这个程序例子,请去掉&&。
&第一个程序dj:
&#include &INCLUDES.H&&
typedef unsigned char u8;
typedef unsigned int u16;
typedef unsigned long u32;
OS_STK TaskStk[3][MaxStkSize];//定义3个堆栈
void task0(void *dat);
void task1(void *dat);
long con1;
long con2;
&& OSInit();
&& InitTimer0( );//初始化系统时钟
&& OSTaskCreate(task0,(void*)0,&TaskStk[0][0],5);//建立任务0 定义好它的优先级等参数
&& OSTaskCreate(task1,(void*)0,&TaskStk[1][0],6);
&& OSStart();
void task0(void *dat)//任务0
& dat=&dat&;& //防止编译有错误
&& while(1)
&&& con1++;
&& OSTimeDly(2);
void task1(void *dat)
&& dat=&dat&;
&& while(1)
&&& con2++;
&&&&vison=OSVersion();//返回系统版本号
&&&&OSTaskDel(6);//删除任务1
& &&OSTimeDly(2);
& & 根据作者建议,最高和最低优先级的任务最好不要使用,而用户使用的任务多达56个,0表示最高优先级。
& & 建立任务的函数有OSTaskCreate和OSTaskCreateExt两个,OSTaskCreateExt函数可以设置更多的任务细节。
& & 在 OSInit()和OSStart()之间最好建立任务和其他要初始化的函数,因为启动系统后,OSStart()将不再执行。
& & OSTimeDly(2)表示将任务0延时2个时钟节拍,在这2个节拍的时间里,系统可以执行任务1;等待2个节拍时间后,系统才返回任务0执行。如果没有延时,系统永远不会执行任务1,而只执行任务0.这个很重要。
& & 想延时更长的时间可以OSTimeDlyHMSM(h,m,s,m)函数,可延时接近11天。
& & 用如果不想让任务0等待2个节拍才返回的话,也可以用OSTimeDlyResume(5)直接恢复任务0运行,这里的5是代表优先级为5的任务;
& & OSTaskDel(6)删除优先级为6的任务,这里的删除不是指删除代码,而是不再执行删除的任务。
& & OSVersion()返回系统版本号的函数,如果是200的话即是2.00版本。
& & OSTaskSuspend(5)表示无条件暂停一个优先级为5的任务,这个时候系统会重新调度,运行下一个优先级最高的任务,如果想恢复该任务,只能用OSTaskResume(5)来恢复。
& & 信号量的使用自己看了几天仍然没搞明白信号量,邮箱,和队列的区别。现在是学习信号量的使用,苦于没有现成的例子参考,只能一步步弄清楚它的,感觉外国人的思维还是和中国的有很大的出入,以至于学习一个国外的技术, 总是先翻译成自己习惯的思维去领会,变成自己的东西。
& & 信号量程序dj:
&& #include &INCLUDES.H&&
&& typedef unsigned char u8;
&& typedef unsigned int u16;
&& typedef unsigned long u32;
&& OS_STK TaskStk[3][MaxStkSize];//定义3个堆栈
&& void task0(void *dat);//定义任务0
&& void task1(void *dat);
&& long con1=0;
&& long con2=0;&
&& OS_EVENT *
&& OSInit();
&& InitTimer0( );
&& sem=OSSemCreate(1);//建立信号量
&& OSTaskCreate(task0,(void*)0,&TaskStk[0][0],5);//建立任务 定义好它的优先级等参数
&& OSTaskCreate(task1,(void*)0,&TaskStk[1][0],6);
&& OSStart();
void task0(void *dat)//任务0
&& while(1)
&&&& con1++;
&&&& OSSemPost(sem);//发送信号量
&&&& OSTimeDly(2);
void task1(void *dat)//任务1
&& while(1)
&&& value=OSSemAccept(sem);&& //查看资源是否可以使用
&&& OSSemPend(sem,0,&err);&&& //等待接收信号 才往下执行任务
&& &con2++;
&&OSTimeDly(2);//延时
& & 信号量的建立必须是在任务级中建立,信号量类型为OS_EVENT&,信号量值可以为1,0,0~65535的值,不同的值代表不同的意义。
& & OSSemAccept(信号量)起查询信号量作用,返回信号量的值。
& & OSSemPend(sem,0,&err);将暂停当前任务,等待信号量的到来。如果 接收到一个信号量(如果信号量大于0) ,该信号量会自动减1,在例子中,信号量开始定义为1,在任务1接收后,信号量会变为0;例子中的OSSemPend(sem,timeout,&err),timeout代表等待timeout个信号量后还没得到信号量,恢复运行状态,如果timeout=0,表示无限等待信号量。
& & 学习uCOSII到现在,开始对信号量,邮箱和队列有了个大概的认识。如果有理解错误,请大家指出。
& & 信号量是一个触发信号,也是一个计数器,等待接收信号的任务一般只有接收到信号才可以执行,否则任务一直暂停。在uCOSII里面,等待信号量的任务可以设置无限等待或等待若干个时钟节拍后,任务自动恢复执行。具体看自己的要求来设置。
& & 邮箱是信号量的扩展,相当于把一个指针定义的变量从一个任务传递到另一个或多个任务中去,这个指针是先发到邮箱,然后等待任务从邮箱里提取指针,这也就传递了指针指向的具体变量值。 等待邮箱的任务也是可以设置无限等待和等待若干个时钟节拍后任务自动恢复执行。后面的队列,我们也可以看得出它们规律,都有各自的建立,删除,发送,接收,查询等功能函数。
& & 队列是多个邮箱的数组,可以看做是个指针数组,任务之间可以按照一定顺序以指针定义的变量来传递,即是发送一个个指针给任务,任务获得指针,来处理指向的变量。这个方式有先进先出,先进后出。这个后面再详谈。
& & 信号量,邮箱,队列的最大不同在于它们发送的内容不同。我觉得这是最根本的区别。
邮箱实例dj:
&#include &INCLUDES.H&&
&typedef unsigned char u8;
&typedef unsigned int u16;
&typedef unsigned long u32;
&OS_STK TaskStk[3][MaxStkSize];//定义3个堆栈
&void task0(void *dat);//定义任务0
&void task1(void *dat);
&long con1=0;
&long con2=0;
&OS_EVENT *C
&& OSInit();
&& InitTimer0();
&& Come=OSMboxCreate((void *)0);//建立邮箱
&& OSTaskCreate(task0,(void*)0,&TaskStk[0][0],5);//建立任务 定义好它的优先级等参数
&& OSTaskCreate(task1,(void*)0,&TaskStk[1][0],6);
&& OSStart();
& void task0(void *dat)//任务0
&& u16 buffer=&0x0FFF&;//要发送的信息
&& while(1)
&&&& con1++;
&&&& OSMboxPost(Come,&buffer);//通过邮箱发送信息(指针)给任务
&&&& OSTimeDly(2);
void task1(void *dat)
&& while(1)
&&& msg=OSMboxPend(Come,0,&err);//等待接收邮箱信息(指针msg指向buffer)&
&&& c=*//获得指针指向的变量
&&& con2++;
&&& OSTimeDly(2);
& &&我们看到,邮箱传递了一个指针从任务0到任务1,任务1使用这个指针来获得变量buffer进行处理。
& & 在这个例子里,设置OSMboxPend(Come,0,&err)中的0表示无限等待邮箱有信息,如果没有,任务1暂停;也可以设置成其他的值N,表示等待N个时钟节拍后如果没有收到信息,任务1自动执行。
& & 这里没用到的邮箱功能函数还有查询邮箱是否有信息,通过邮箱发信息给多个任务等。
& & 对消息队列的学习理解有点难,对技术来说,一本好的书一般是原理和例子相结合的,可惜我找到的很少。书上说消息队列实际上是多个邮箱组成的数组,是一个列表。这个数组其实是个指针数组,里面每个指针可以指向不同类型的变量,通过传递一个个指针,我们可以做到传递指针所指向的一个个变量。(顺便复习下,一个邮箱只能传递一个指针,而队列可传递多个)。
#include &INCLUDES.H&&
typedef unsigned char u8;
typedef unsigned int u16;
typedef unsigned long u32;
OS_STK TaskStk[3][MaxStkSize];//定义3个堆栈
void task0(void *dat);//定义任务0
void task1(void *dat);//定义任务1
long con1=0;
long con2=0;
OS_EVENT *Com1;&&& //定义一个指针
void *ComMsg1[3]; //定义一个指针数组&
u8 st[4]={0x01,0x02,0x03,0x04};//定义一个数组
u8 aa[4]={0x05,0x04,0x06,0x09};//定义一个数组
u8& a1=0xFF;//定义一个数
&& OSInit();//初始化ucosii
&& InitTimer0();
&& Com1=OSQCreate(&ComMsg1[0],3);//建立一个消息队列(即为数组指针) 消息内存大小为3
&& OSQPost(Com1,(void*)&st[0]);&&&&&&&&& //发送到队列&
&& OSQPost(Com1,(void*)&aa[0]);&&&&&&&&&//发送到队列&
&& OSQPost(Com1,(void*)&a1);&&&&&&&&&&&& //发送到队列&
&& OSTaskCreate(task0,(void*)0,&TaskStk[0][0],5);//建立任务 定义好它的优先级等参数
&& OSTaskCreate(task1,(void*)0,&TaskStk[1][0],6);
&& OSStart();//系统启动
void task0(void *dat)//任务0
// & dat=&dat&;//防止编译有错误
&& while(1)
&&&& con1++;
&&&& OSTimeDly(2);
void task1(void *dat)
&& u8 *msg1;
&& u8 cc,b;
// & dat=&dat&;//防止编译有错误
&& while(1)
&& msg1=OSQPend(Com1,0,&err);
& cc=*msg1;
& b=*(msg1+1);
& con2++;
&& OSTimeDly(2);
Com1=OSQCreate(&ComMsg1[0],3),建立一个队列,将*Com1指针将指向队列指针数组*ComMsg1[3]的首地址。3表示内存大小。
& & OSQPost(Com1,(void*)&st[0]),是以先入先出发送消息到队列,由*ComMsg1[0]指向数组st的首地址,同时队列消息数加一。
& & OSQPost(Com1,(void*)&aa[0])发一个消息给队列,此时是由*ComMsg1[1]指向aa数组的首地址,同时队列消息数加1。;&依此类推,发下一个也是一样。(如果队列满了,再发送消息到队列的话,队列将会出现错误)。
& & msg1=OSQPend(Com1,0,&err);是等待消息队列函数,获得指针数组里的第一个指针ComMsg1[0],该指针指向st[0],。cc=*msg1是通过指针获得指向的具体值st[0]=0x01;如果再调用一次msg1=OSQPend(Com1,0,&err),将获得指针数组里下一个指针ComMsg1[1],依此类推。
& & 每调用一次OSQPend函数,该函数会将队列的消息减1,Com1指向下一个消息指针*ComMsg1[i++],直到队列完全没有消息为止。在例子中,只有3个消息,程序将执行3次任务1后,队列已经没有消息了,所以将任务1暂停。
原文地址:http://cspiao1986./blog/static/
该系列主要转自:
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:54953次
排名:千里之外
转载:22篇
(4)(17)(4)

我要回帖

更多关于 ucosiii 信号量 的文章

 

随机推荐