版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第六章同步、互斥与通信事件总之,多个任务共享同一资源或有工作顺序要求时,在正式工作之前要互相打招呼。黄宏:别走啊!宋丹丹:我自己的腿,我爱走就走,你管不着!黄宏:腿是你自己的,但手是咱俩的呀!宋丹丹黄宏事件的类型信号量邮箱和消息队列标志事件的功用多任务系统中任务之间的关系相互独立仅竞争CPU资源竞争除CPU外的其他资源(互斥)同步协调彼此运行的步调通信彼此间传递数据或信息,以协同完成某项工作一个简单的信号量1/0收信方发信方共享资源通用函数PendPostCreateDelete举例:信号量类型的Pend和Post任务要得到信号量,执行等待操作(pend)。如果信号量有效(非0),则信号量减1,任务得以继续运行。如果信号量无效,则等待信号量的任务就被列入等待信号量的任务表中。等待超时,该信号量还是无效,则等待该信号量的任务进入就绪态,准备运行,并返回出错代码(等待超时错误)。任务释放信号量,执行发信号(post)操作如果没有任务等待信号量,那么信号量的值仅是简单的加1(则信号量大于0,有效);如果有任务等待该信号量,那么就会有另一个任务进入就绪态,信号量的值就不加1。TaskxTaskyPOSTPENDISRxTaskyPOSTPENDTaskxTaskyPOSTPENDPOSTPEND任务与任务之间的同步(单向)任务与ISR之间的同步(单向)任务与任务之间的同步(双向)抽象数据结构内部实现机制实例说明
-µC/OS-II事件控制块ECB-同步与通信机制的基本数据结构typedefstruct{INT8U OSEventType;//事件类型INT8U OSEventGrp;//等待任务所在的组INT16U OSEventCnt;//计数器(信号量)void *OSEventPtr;//指向消息或消息队列的指针INT8U OSEventTbl[OS_EVENT_TBL_SIZE];//等待任务列表}OS_EVENT;抽象数据结构内部实现机制实例说明
-µC/OS-II当一个事件发生后,等待事件列表中优先级最高的任务(即在.OSEventTbl[]&OSEventGrp中所有被置1的位中优先级数值最小的任务)得到该事件。抽象数据结构内部实现机制实例说明
-µC/OS-II当.OSEventTbl[n]中的任何一位为1时,OSEventGrp中的第n位为1。与任务就绪列表类似!抽象数据结构内部实现机制实例说明
-µC/OS-II将一个任务插入到等待事件的任务列表中:pevent->OSEventGrp|=OSMapTbl[prio>>3];pevent->OSEventTbl[prio>>3]|=OSMapTbl[prio&0x07];与将一个任务插入到就绪列表中的操作类似!IndexBitmask(Binary)0 000000011 000000102 000001003 000010004 000100005 001000006 010000007 10000000信号量内部实现机制实例说明
-µC/OS-II从等待事件的任务列表中使任务脱离等待状态if((pevent->OSEventTbl[prio>>3]&=~OSMapTbl[prio&0x07])==0){pevent->OSEventGrp&=~OSMapTbl[prio>>3];}与将任务从就绪列表中清除的操作类似!信号量内部实现机制实例说明
-µC/OS-II在等待事件的任务列表中查找优先级最高的任务y=OSUnMapTbl[pevent->OSEventGrp];x=OSUnMapTbl[pevent->OSEventTbl[y]];prio=(y<<3)+x;与查找优先级最高的就绪任务的操作类似!抽象数据结构内部实现机制实例说明
-µC/OS-II第一节
信号量信号量的种类及用途信号量用于实现任务与任务之间、任务与中断处理程序之间的同步与互斥。信号量一般分为三种:互斥问题的互斥信号量。它比较特殊,可能会引起优先级反转问题。解决同步问题的二值信号量。解决资源计数问题的计数信号量。将信号量进行种类细分,可以根据其用途,在具体实现时做专门处理,提高执行效率和可靠性。互斥信号量用互斥信号量保护的代码区称作“临界区”,临界区代码通常用于对共享资源的访问。互斥信号量的值被初始化成1,表明目前没有任务进入“临界区”,但最多只有一个任务可以进入“临界区”。第一个试图进入“临界区”的任务将成功获得互斥信号量,而随后试图进入用同一信号量保护的临界区的所有其他任务就必须等待。当任务离开“临界区”时,它将释放信号量并允许正在等待该信号量的任务进入“临界区”。Task1Task2共享资源二值信号量二值信号量主要用于任务与任务之间、任务与中断服务程序之间的同步用于同步的二值信号量初始值为0,表示同步事件尚未产生;任务申请信号量以等待该同步事件的发生;另一个任务或ISR到达同步点时,释放信号量(将其值设置为1)表示同步事件已发生,以唤醒等待的任务。二值信号量availableunavailableacquire(value=0)release(value=1)Initialvalue=0二值信号量状态图Task1(){……
执行一些操作;
将信号量sem1置1;
申请信号量sem2;…………}Task2(){……
申请信号量sem1;
执行一些操作;
将信号量sem2置1;…………}Task2申请信号量sem1失败,系统切换到Task1sem1被置1后,Task2得到sem1并抢占Task1Task2运行到某处时因某种原因被阻塞,系统切换到Task1用二值信号量实现两个任务之间的双向同步Task2优先级高于Task1sem1和sem2的初始值均为0计数信号量计数信号量用于控制系统中共享资源的多个实例的使用,允许多个任务同时访问同一种资源的多个实例计数信号量被初始化为n(非负整数),n为该种共享资源的数目。Task1Task2共享资源实例nTaskm共享资源实例1…………计数信号量availableunavailableInitialcount>0acquire(count=0)release(count=1)Initialcount=0计数信号量状态图acquire(count=count-1)release(count=count+1)计数信号量1234…………n生产者任务消费者任务计数信号量使用实例:有界缓冲问题生产者任务do{…产生一个数据项…申请empty申请mutex…将新生成的数据项添加到缓冲中…释放mutex释放full}while(1);消费者任务do{申请full申请mutex…从缓冲中移出一个数据项的内容…释放mutex释放empty…消费新获得的数据项内容…}while(1);计数信号量full:已被填充的数据项数目,取值范围0-n,初始值为0计数信号量empty:空闲数据项数目,取值范围为0-n,初始值为n;互斥信号量mutex:控制生产者任务和消费者任务对有界缓冲的访问,初始值为1。信号量机制的主要数据结构信号量控制块:事件控制块+类型为信号量信号量的类型互斥信号量(MUTEX_SEMAPHORE)计数信号量(COUNTING_SEMAPHORE)二值信号量(BINARY_SEMAPHORE)信号量
——主要函数信号量的主要功能创建信号量获取(申请)信号量释放信号量删除信号量获取有关信号量的各种信息创建信号量功能:根据应用传递的参数创建一个信号量参数:信号量的名字、属性和初始值等。内核动作:从空闲信号量控制块链中分配一个信号量控制块,并初始化信号量属性。创建成功时,为其分配唯一的ID号返回给应用。如果已创建信号量数量已达到用户配置的最大数量,就返回错误。创建信号量信号量的属性包括其类型、任务等待信号量的方式(即排列的顺序)、解决优先级反转的策略。信号量的类型互斥信号量(MUTEX_SEMAPHORE)计数信号量(COUNTING_SEMAPHORE)二值信号量(BINARY_SEMAPHORE)创建信号量任务等待信号量的方式
先进先出(FIFO)顺序优先级(PRIORITY)顺序优先级反转问题的解决方法(只适用于互斥信号量)优先级继承算法(INHERIT_PRIORITY)优先级天花板算法(PRIORITY_CEILING),需给出所有可能获得此信号量的任务中优先级最高的任务的优先级。创建一个信号量OSSemCreate()OS_EVENT*OSSemCreate(INT16Ucnt){ OS_EVENT*pevent; pevent=OSEventFreeList;//从空闲事件控制块链中取得一个ECB if(OSEventFreeList!=(OS_EVENT*)0){ OSEventFreeList=(OS_EVENT*)OSEventFreeList->OSEventPtr; } if(pevent!=(OS_EVENT*)0){//初始化ECB的各个域
pevent->OSEventType=OS_EVENT_TYPE_SEM;//事件类型为信号量
pevent->OSEventCnt=cnt;//信号量的初始计数值
pevent->OSEventPtr=(void*)0; OS_EventWaitListInit(pevent);//初始化等待任务列表
} return(pevent);//调用者需检查返回值,如果为NULL则表示建立失败}获取(申请)信号量功能:试图获得应用指定的信号量。if 信号量的值大于0then 将信号量的值减1else 根据接收信号量的选项,将任务放到等待队列中,或是直接返回获取(申请)信号量当所申请的信号量不能被立即获得时,可以有以下几种选择:永远等待不等待,立即返回,并返回一个错误状态码指定等待时限(可有效避免死锁)注意:不允许在ISR中选择等待当任务选择等待时,将被按FIFO或优先级顺序放置在等待队列中获取(申请)信号量如果任务等待一个使用优先级继承算法的互斥信号量,且它的优先级高于当前正占有此信号量的任务的优先级,那么占有信号量的任务将继承这个被阻塞的任务的优先级。如果任务成功地获得一个采用优先级天花板算法的互斥信号量,它的优先级又低于优先级天花板,那么它的优先级将被抬升至天花板。
获取(等待)一个信号量OSSemPend()voidOSSemPend(OS_EVENT*pevent,INT16Utimeout,INT8U*err){ if(pevent->OSEventCnt>0){//信号量值大于0,成功获得信号量并返回
pevent->OSEventCnt--; *err=OS_NO_ERR; return;} OSTCBCur->OSTCBStat|=OS_STAT_SEM;//设置任务状态为等待信号量
OSTCBCur->OSTCBDly=timeout;//设置等待时限
OS_EventTaskWait(pevent);//将任务放置到信号量的等待列表中
OS_Sched();//内核实施任务调度,系统切换到另一就绪任务执行
if(OSTCBCur->OSTCBStat&OS_STAT_SEM){//判断任务恢复执行的原因,如果等待时限超时但仍然未获得信号量,则返回超时信息
OSEventTO(pevent); *err=OS_TIMEOUT; return;} OSTCBCur->OSTCBEventPtr=(OS_EVENT*)0; *err=OS_NO_ERR;//任务由于获得信号量而恢复执行,本调用成功返回}获取(无等待地请求)一个信号量OSSemAccept()INT16UOSSemAccept(OS_EVENT*pevent){ INT16Ucnt; cnt=pevent->OSEventCnt; if(cnt>0){ pevent->OSEventCnt--; } return(cnt);}注意:即使不能成功获得信号量(返回值为0),调用者也不会被阻塞。此函数可以在中断处理程序中使用。释放一个信号量OSSemPost()INT8UOSSemPost(OS_EVENT*pevent){ if(pevent->OSEventGrp!=0x00){//如果有任务在等待该信号量
OS_EventTaskRdy(pevent,(void*)0,OS_STAT_SEM);//使等待任务列表中优先级最高的任务就绪
OS_Sched();//内核实施任务调度
return(OS_NO_ERR);//成功返回
} if(pevent->OSEventCnt<65535){//如果没有任务等待该信号量,并且信号量的值未溢出
pevent->OSEventCnt++;//信号量的值加1 return(OS_NO_ERR);//成功返回
} return(OS_SEM_OVF);//信号量溢出}删除信号量功能:从系统中删除应用指定的一个信号量内核动作:将信号量控制块返还给系统删除信号量的不一定是创建信号量的任务如果有任务正在等待获得该信号量,执行此功能将使所有等待这个信号量的任务回到就绪队列中,且返回一个状态码指示该信号量已被删除删除一个信号量OSSemDel()OS_EVENT*OSSemDel(OS_EVENT*pevent,INT8Uopt,INT8U*err){ BOOLEANtasks_waiting; if(pevent->OSEventGrp!=0x00{//根据是否有任务在等待信号量设置等待标志
tasks_waiting=TRUE; }else{ tasks_waiting=FALSE; } switch(opt){ caseOS_DEL_NO_PEND://如果有任务等待信号量则不删除信号量
if(task_waiting==FALSE{//没有任务等待,释放ECB回空闲链
pevent->OSEventType=OS_EVENT_TYPE_UNUSED; pevent->OSEventPtr=OSEventFreeList; OSEventFreeList=pevent;//调整空闲ECB链头指针 *err=OS_NO_ERR; return((OS_EVENT)0); }else{ *err=OS_ERR_TASK_WAITING;//有任务等待,删除信号量失败
return(pevent); }删除一个信号量OSSemDel() caseOS_DEL_ALWAYS://无论有无任务等待都删除信号量
//将等待列表中的每个任务都设置成就绪
while(pevent->OSEventGrp!=0x00){ OS_EventTaskRdy(pevent,(void*)0,OS_STAT_SEM);}
//释放该信号量的ECB回空闲控制块链
pevent->OSEventType=OS_EVENT_TYPE_UNUSED; pevent->OSEventFreeList; OSEventFreeList=pevent;
//如果之前有任务等待信号量,内核实施任务调度
if(tasks_waiting==TRUE){OS_Sched();} *err=OS_NO_ERR; return((OS_EVENT*)0); default: *err=OS_ERR_INVALID_OPT; return(pevent); }}第二节
邮箱和消息队列概述任务间的通信方式Send(P,message)–
发送一个消息到任务PReceive(Q,message)–
从任务Q接收一个消息
概述消息队列:属于间接通信方式消息:内存空间中一段长度可变的缓冲区,其长度和内容均可以由用户定义,其内容可以是实际的数据、数据块的指针或空。概述一些操作系统内核把消息进一步分为:邮箱和消息队列邮箱仅能存放单条消息,它提供了一种低开销的机制来传送信息。每个邮箱可以保存一条大小为若干个字节的消息。消息队列可存放若干消息,提供了一种任务间缓冲通信的方法。消息机制可支持定长与可变长度两种模式的消息,可变长度的消息队列需要对队列中的每一条消息增加额外的存储开销。消息队列机制的主要数据结构消息队列控制块管理所有创建的消息队列,系统运行时动态分配和回收消息队列控制块消息队列缓冲区存放发送到该队列的消息,接收者从缓冲区中取出消息。消息的发送或接收有两种方法(影响消息缓冲区结构):将数据从发送任务的空间完全拷贝到接收任务的空间中(效率较低,执行时间与消息大小有关)只传递指向数据存储空间的指针(提高系统性能)SendingTaskReceivingTaskMessage1Message1Message1发送任务的内存区域消息队列的内存区域接收任务的内存区域1stcopy2ndcopy发送和接收消息的消息拷贝和内存使用这种消息传递方法效率低、占用空间大一种效率更高的方式是传递消息指针number_of_messagemax_message_countnumber_of_messagemax_message_sizewait_disciplinewait_queuequeue_startqueue_inqueue_outqueue_endmessagemessagemessagemessagemessagemessagemessagemessagemessagemax_message_count消息队列控制块消息队列缓冲区消息队列机制的主要数据结构消息队列的环形缓冲消息队列机制的主要数据结构使用消息队列可以在任务之间传递多条消息。消息队列由三个部分组成:事件控制块、消息队列和消息。当把事件控制块成员OSEventType的值置为OS_EVENT_TYPE_Q时,该事件控制块描述的就是一个消息队列。消息队列的数据结构如图4-21所示。从图中可以看到,消息队列相当于一个共用一个任务等待列表的消息邮箱数组,事件控制块成员OSEventPtr指向了一个叫做队列控制块(OS_Q)的结构,该结构管理了一个数组MsgTbl[],该数组中的元素都是一些指向消息的指针。其中,可以移动的指针为OSQIn和OSQOut,而指针OSQStart和OSQEnd只是一个标志(常指针)。当可移动的指针OSQIn或OSQOut移动到数组末尾,也就是与OSQEnd相等时,可移动的指针将会被调整到数组的起始位置OSQStart。也就是说,从效果上来看,指针OSQEnd与OSQStart等值。于是,这个由消息指针构成的数组就头尾衔接起来形成了一个如图所示的循环的队列。为了对图所示的消息指针数组进行有效的管理,μC/OS-II把消息指针数组的基本参数都记录在一个叫做队列控制块的结构中,队列控制块的结构如下:
typedefstructos_q{structos_q*OSQPtr;void**OSQStart;void**OSQEnd;void **OSQIn;void**OSQOut;INT16UOSQSize;INT16UOSQEntries;}OS_Q;在μC/OS-II初始化时,系统将按文件OS_CFG.H中的配置常数OS_MAX_QS定义OS_MAX_QS个队列控制块,并用队列控制块中的指针OSQPtr将所有队列控制块链接为链表。由于这时还没有使用它们,故这个链表叫做空队列控制块链表创建一个消息队列首先需要定义一指针数组,然后把各个消息数据缓冲区的首地址存入这个数组中,然后再调用函数OSQCreate()来创建消息队列。创建消息队列函数OSQCreate()的原型为:
OS_EVENTOSQCreate(void**start, //指针数组的地址INT16Usize //数组长度);请求消息队列的目的是为了从消息队列中获取消息。任务请求消息队列需要调用函数OSQPend(),该函数的原型为:
void*OSQPend(OS_EVENT*pevent, //所请求的消息队列的指针INT16Utimeout, //等待时限INT8U*err //错误信息);任务需要通过调用函数OSQPost()或OSQPostFront()来向消息队列发送消息。函数OSQPost()以FIFO(先进先出)的方式组织消息队列,函数OSQPostFront()以LIFO(后进先出)的方式组织消息队列。这两个函数的原型分别为:
INT8UOSQPost(OS_EVENT*pevent, //消息队列的指针void*msg //消息指针);
和
INT8UOSQPost(OS_EVENT*pevent, //消息队列的指针void*msg //消息指针);
函数中的参数msg为待发消息的指针。消息队列的主要函数消息队列的主要功能创建消息队列发送普通消息发送紧急消息发送广播消息接收消息删除消息队列获取有关消息队列的各种信息创建消息队列创建消息队列时,调用者可以指定如下参数:消息的最大长度每个消息队列中最多的消息数消息队列的属性任务等待消息时的排队方式:FIFO或PRIORITY系统为新创建的消息队列分配唯一的ID发送消息根据紧急程度的不同,消息通常可分为普通消息与紧急消息。如果有任务正在等待消息(即消息队列为空),则普通消息发送和紧急消息发送的执行效果是一样的。任务从等待队列移到就绪队列中,消息被拷贝到任务提供的缓冲区中(或者由接收任务得到指向消息的指针)。如果没有任务等待,发送普通消息将消息放在队列尾,而发送紧急消息将消息放在队列头。发送消息Msg3接收任务等待列表Msg2Msg1消息队列发送普通消息-先进先出(FIFO)次序Msg3接收任务等待列表Msg2Msg1消息队列发送紧急消息-后进先出(LIFO)次序发送消息如果发送消息时队列已被填满,则不同的操作系统可能采取不同的处理办法:挂起试图向已满的消息队列中发送消息的任务(不适用于中断服务程序)简单地丢弃该条消息并向调用者返回错误信息广播消息。在此之前所有试图从队列中接收消息的任务此时都将获得相同的消息。该功能拷贝消息到各任务的消息缓冲中(或者让所有的等待任务得到指向消息的指针),并唤醒所有的等待任务。接收消息如果指定的消息队列中有消息,则将其中的第一条消息拷贝到调用者的缓冲区(或者将第一条消息指针传递给调用者),并从消息队列中删除它。如果此时消息队列中没有消息,则可能出现以下几种情况:永远等待消息的到达:等待消息的任务按FIFO或优先级高低顺序排列在等待队列中等待消息且指定等待时限:等待消息的任务按FIFO或优先级高低顺序排列在等待队列中不等待,强制立即返回接收消息限时等待可有效预防死锁中断服务程序接收消息时必须选择不等待,因为中断服务程序是不能被阻塞的。如果消息队列被应用删除,则所有等待该消息队列的任务都被返回一个错误信息,并回复到就绪状态。接收消息Task4High消息队列接收任务等待列表任务等待列表-基于优先级的次序Task2mediumTask3mediumTask1LowTask4High消息队列接收任务等待列表任务等待列表-先进先出(FIFO)次序Task2mediumTask3mediumTask1Low删除消息队列从系统中删除指定的消息队列,释放消息队列控制块及消息队列缓冲区。任何知道此消息队列ID号的代码都可以删除它。消息队列被删除后,所有等待从这个消息队列接收消息的任务都回到就绪态,并得到一个错误信息表明消息队列已被删除。邮箱如果把数据缓冲区的指针赋给一个事件控制块的成员OSEventPrt,同时使事件控制块的成员OSEventType为常数OS_EVENT_TYPE_MBOX,则该事件控制块就叫做消息邮箱,消息邮箱是在两个需要通信的任务之间通过传递数据缓冲区指针的方法来通信的。
创建邮箱需要调用函数OSMboxCreate(),这个函数的原型为:
OS_EVENT*OSMboxCreate(void*msg //消息指针);函数中的参数msg为消息的指针,函数的返回值为消息邮箱的指针。调用函数OSMboxCreate()需先定义msg的初始值。在一般的情况下,这个初始值为NULL;但也可以事先定义一个邮箱,然后把这个邮箱的指针作为参数传递到函数OSMboxCreate()中,使之一开始就指向一个邮箱。
任务可以通过调用函数OSMboxPost()向消息邮箱发送消息,这个函数的原型为:
INT8UOSMboxPost(OS_EVENT*pevent, //消息邮箱指针void*msg //消息指针);当一个任务请求邮箱时需要调用函数OSMboxPend(),这个函数的主要作用就是查看邮箱指针OSEventPtr是否为NULL,如果不是NULL就把邮箱中的消息指针返回给调用函数的任务,同时用OS_NO_ERR通过函数的参数err通知任务获取消息成功;如果邮箱指针OSEventPtr是NULL,则使任务进入等待状态,并引发一次任务调度。函数OSMboxPend()的原型为:
void*OSMboxPend(OS_EVENT*pevent, //请求消息邮箱指针INT16Utimeout, //等待时限INT8U*err //错误信息);第三节
事件集概述在嵌入式实时内核中,事件是指一种表明预先定义的系统事件已经发生的机制。事件机制用于任务与任务之间、任务与ISR之间的同步。其主要的特点是可实现一对多的同步。
一个事件就是一个标志,不具备其它信息。一个或多个事件构成一个事件集。事件集可以用一个指定长度的变量(比如一个32位的无符号整型变量,不同的操作系统其具体实现不一样)来表示,而每个事件由在事件集变量中的某一位来代表。概述事件及事件集有以下特点:事件间相互独立事件仅用于同步,不提供数据传输功能事件无队列,即多次发送同一事件,在未经过任何处理的情况下,其效果等同于只发送一次。提供事件机制的意义在于:当某任务要与多个任务或中断服务同步时,就需要使用事件机制。若任务需要与一组事件中的任意一个发生同步,可称为独立型同步(逻辑“或”关系)。任务也可以等待若干事件都发生时才同步,称为关联型同步(逻辑“与”关系)。“或”同步和“与”同步概述用多个事件的组合发信号给多个任务概述术语:发送事件集。指在一次发送过程中发往接收者(比如任务)的一个或多个事件的组合。待处理事件集。指已被发送到一个接收者但还没有被接收(即正在等待处理)的所有事件的集合。事件条件。指事件接收者在一次接收过程中期待接收的一个或多个事件的集合。“或”同步:待处理事件集只要包括事件条件中的任一事件即可满足要求;“与”同步:其二是待处理事件集必须包括事件条件中的全部事件方可满足要求。概述事件机制的主要数据结构事件集控制块:管理所有创建的事件集或者事件集附属于任务,不需创建,其相关参数成为任务控制块的一部分事件的内部实现机制实例说明-µC/OS-II事件标志组数据结构typedefstruct{ INT8U OSFlagType;//指示本数据结构的类型
void *OSFlagWaitList;//等待事件标志的任务链表
OS_FLAGS OSFlagFlags;//各事件标志的当前状态}OS_FLAG_GRP;事件标志节点事件标志节点数据结构typedefstruct{ void *OSFlagNodeNext;//后驱指针
void *OSFlagNodePrev;//前驱指针
void *OSFlagNodeTCB;//任务控制块指针
void *OSFlagNodeFlagGrp;//指回OS_FLAG_GRP结构
OS_FLAGS OSFlagNodeFlags;//所等待的事件标志组合
INT8U OSFlagNodeWaitType;//等待类型(与、或)}OS_FLAG_NODE;#define水0x01
#define米0x02
#define青菜0x04
#define肉0x08staticvoidTask_做饭(void*pdata)
{
While(1){
OSFlagPend(eflag,水|米,OS_FLAG_WAIT_SET_ALL,0,&err);//等待水、米全部到齐后开始做饭
}
}staticvoidTask_做菜(void*pdata)
{
While(1){
OSFlagPend(eflag,青菜|肉,OS_FLAG_WAIT_SET_ANY,0,&err);//青菜或者肉有一样到位了就可以开始做菜啦
}
}staticvoidTask_打水(void*pdata)
{
While(1){
OSFlagPost(eflag,水,OS_FLAG_SET,&err);
}
}staticvoidTask_买米(void*pdata)
{
While(1){
OSFlagPost(eflag,米,OS_FLAG_SET,&err);
}
}事件标志组、事件标志节点及任务控制块之间的关系事件集
——主要功能函数事件集的主要功能创建事件集删除事件集发送事件(集)接收事件(集)获取有关事件集的各种信息创建事件集申请空闲事件集控制块,设置事件集属性,初始化控制块中的域,分配ID号创建一个事件标志组OSFlagCreate()OS_FLAG_GRP*OSFlagCreate(OS_FLAGSflags,INT8U*err){ OS_FLAG_GRP*pgrp; pgrp=OSFlagFreeList;//获取一个空闲事件标志组结构
if(pgrp!=(OS_FLAG_GRP*)0){//获取成功,初始化该结构中的域
OSFlagFreeList=(OS_FLAG_GRP*)OSFlagFreeList->OSFlagWaitList;//调整空闲结构链头指针
pgrp->OSFlagType=OS_EVENT_TYPE_FLAG; pgrp->OSFlagFlags=flags;//初始化当前各事件标志的状态
pgrp->OSFlagWaitList=(void*)0;//尚无任务等待事件标志 *err=OS_NO_ERR; }else{*err=OS_FLAG_GRP_DEPLETED;} return(pgrp); }接收事件(集)在接收事件(集)时可以有如下选项,每一类只能选择其一:接收事件(集)时可等待(WAIT)接收者永远等待,直到事件条件被满足后成功返回;接收者根据指定的时限等待。接收事件(集)时不等待(NO_WAIT)待处理事件集必须包含事件条件中的全部事件方可满足要求(EVENT_ALL),即按照“与”条件接收事件待处理事件集只要包含事件条件中的任一事件即可满足要求(EVENT_ANY),即按照“或”条件接收事件接收(等待)事件标志组的事件标志位OSFlagPend()OS_FLAGSOSFlagPend(OS_FLAG_GRP*pgrp,OS_FLAGSflags,INT8Uwait_type,INT16Utimeout,INT8U*err){ OS_FLAG_NODEnode;//OS_FLAG_NODE作为局部变量存在于调用该函数的任务堆栈中
OS_FLAGSflags_cur; OS_FLAGSflags_rdy; switch(wait_type){ caseOS_FLAG_WAIT_SET_ALL://任务以“与”方式等待事件标志
flags_rdy=pgrp->OSFlagFlags&flags; if(flags_rdy==flags){//事件标志当前状态与等待条件相符
pgrp->OSFlagFlags&=~flags_rdy;//清除(即“消费”)满足条件的事件标志
flags_cur=pgrp->OSFlagFlags; *err=OS_NO_ERR; return(flags_cur);//返回处理后的事件标志组
}else{OS_FlagBlock(pgrp,&node,flags,wait_type,timeout);}
//事件标志当前状态与等待条件不相符,任务被阻塞
break;接收(等待)事件标志组的事件标志位OSFlagPend() caseOS_FLAG_WAIT_SET_ANY://任务以“或”方式等待事件标志
flags_rdy=pgrp->OSFlagFlags&flags; if(flags_rdy!=(OS_FLAGS)0){//有满足条件的事件标志
pgrp->OSFlagFlags&=~flags_rdy;//清除(即“消费”)满足条件的事件标志
flags_cur=pgrp->OSFlagFlags; *err=OS_NO_ERR; return(flags_cur);//返回处理后的事件标志组
}else{OS_FlagBlock(pgrp,&node,flags,wait_type,timeout);} //事件标志当前状态与等待条件不相符,任务被阻塞
break; default: flags_cur=(OS_FLAGS)0; *err=OS_FLAG_ERR_WAIT_TYPE; return(flags_cur); }接收(等待)事件标志组的事件标志位OSFlagPend() OS_Sched();//当前任务被放到事件标志等待链后,内核实施任务调度
if(OSTCBCur->OSTCBStat&OS_STAT_FLAG){//判断任务重新就绪的原因,如果是等待超时
OS_FlagUnlink(&node);//将任务从事件标志等待链中解除下来
OSTCBCur->OSTCBStat=OS_STAT_RDY;//设置当前任务状态为就绪
flags_cur=(OS_FLAGS)0;//无效的事件标志状态 *err=OS_TIMEOUT;//超时信号
}else{//任务重新就绪的原因是在限定时间得到了满足条件的事件标志
pgrp->OSFlagFlags&=~OSTCBCur->OSTCBFlagsRdy;//清除(即“消费”)满足条件的事件标志
flags_cur=pgrp->OSFlagFlags; *err=OS_NO_ERR; } return(flags_cur);}添加一个任务到事件标志组等待任务链表中OS_FlagBlock()接收(无等待地获取)事件标志OSFlagAccept()OS_FLAGSOSFlagAccept(OS_FLAG_GRP*pgrp,OS_FLAGSflags,INT8Uwait_type,INT8U*err){ OS_FLAGSflags_cur,flags_rdy; *err=OS_NO_ERR; switch(wait_type){//判断等待事件标志的方式
caseOS_FLAG_WAIT_SET_ALL://”与”方式等待
flags_rdy=pgrp->OSFlagFlags&flags; if(flags_rdy==flags)pgrp->OSFlagFlags&=~flags_rdy;//事件标志当前状态与等待条件相符,清除(即“消费”)相应的事件标志
else*err=OS_FLAG_ERR_NOT_RDY;//不符合条件,返回错误信息
flags_cur=pgrp->OSFlagFlags; break;接收(无等待地获取)事件标志OSFlagAccept()caseOS_FLAG_WAIT_SET_ANY://”或”方式等待
flags_rdy=pgrp->OSFlagFlags&flags; if(flags_rdy!=(OS_FLAGS)0) pgrp->OSFlagFlags&=~flags_rdy;//事件标志当前状态与等待条件相符,清除(即“消费”)相应的事件标志
else*err=OS_FLAG_ERR_NOT_RDY;//不符合条件,返回错误信息
flags_cur=pgrp->OSFlagFlags; break;default: flags_cur=(OS_FLAGS)0;//0表示无效的事件标志组 *err=OS_FLAG_ERR_WAIT_TYPE;//错误的等待类型
break;}return(flags_cur);}发送事件(集)调用者(任务或中断)构造一个事件(集),将其发往接收者(比如目标任务)。可能会出现以下几种情况之一:目标任务正在等待的事件条件得到满足,任务就绪;目标任务正在等待的事件条件没有得到满足,该事件(集)被按“或”操作,保存到目标任务的待处理事件集中,目标任务继续等待;目标任务未等待事件(集),该事件(集)被按“或”操作,保存到目标任务的待处理事件集中。发送(置位)事件标志组中的事件标志OSFlagPost()OS_FLAGSOSFlagPost(OS_FLAG_GRP*pgrp,OS_FLAGSflags,INT8U*err){ OS_FLAG_NODE*pnode; BOOLEANsched=FALSE;//初始化调度标志
OS_FLAGSflags_cur,flags_rdy; pgrp->OSFlagFlags|=flags;//置位事件标志
pnode=(OS_FLAG_NODE*)pgrp->OSFlagWaitList;//获取任务等待链头节点
while(pnode!=(OS_FLAG_NODE*)0){//如果有任务等待,遍历等待链
switch(pnode->OSFlagNodeWaitType){ caseOS_FLAG_WAIT_SET_ALL://”与”方式等待
flags_rdy=pgrp->OSFlagFlags&pnode->OSFlagNodeFlags; if(flags_rdy==pnode->OSFlagNodeFlags){//符合等待条件
if(OS_FlagTaskRdy(pnode,flags_rdy)==TRUE) sched=TRUE;//如果任务就绪,设置调度标志
} break;发送(置位)事件标志组中的事件标志OSFlagPost() caseOS_FLAG_WAIT_SET_ANY://”或”方式等待
flags_rdy=pgrp->OSFlagFlags&pnode->OSFlagNodeFlags;if(flags_rdy!=(OS_FLAGS)0){//有满足条件的事件标志
if(OS_FlagTaskRdy(pnode,flags_rdy)==TRUE) sched=TRUE;//如果任务就绪,设置调度标志
}break; } p
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 纯化水系统试题及答案
- 护理疼痛管理与控制
- 呼吸系统疾病患者的护理教育
- 呼吸衰竭患者电解质紊乱的护理
- 宫颈炎的护理评估
- 呼吸系统疾病患者的护理人文关怀
- 护理沟通中的文化差异与应对
- 护理跨文化护理:应对多元文化
- 护理教育:模拟教学与技能训练
- 【高考真题】黑龙江省2026年高考生物试卷(解析版)
- 保险考试基础知识试题库及答案
- 诊所挂证医师免责协议书
- 家装工长培训课件
- 深度解析(2026)《HJT 55-2000大气污染物无组织排放监测技术导则》(2026年)深度解析
- 物体打击安全教育培训课件
- 2026年四川高考理科综合真题试卷及答案
- 精神障碍患者家属护理常识讲座
- IMPA船舶物料指南(电子版)
- 2025年事业单位工勤人员技师考试职业道德复习题(附答案)
- 人教版高中地理必修第二册期末复习重点知识背诵提纲
- 在职攻读博士管理办法
评论
0/150
提交评论