《同步互斥与 通信幻灯片.ppt》由会员分享,可在线阅读,更多相关《同步互斥与 通信幻灯片.ppt(100页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、同步互斥与 通信第1页,共100页,编辑于2022年,星期五2023/1/2主要内容信号量邮箱和消息队列事件异步信号*第2页,共100页,编辑于2022年,星期五2023/1/3概述多任务系统中任务之间的关系相互独立 仅竞争CPU资源竞争除CPU外的其他资源(互斥)同步 协调彼此运行的步调通信 彼此间传递数据或信息,以协同完成某项工作第3页,共100页,编辑于2022年,星期五2023/1/4任务能以以下方式与中断处理程序或其他任务进行同步或通信:单向同步或通信:一个任务与另一个任务或一个ISR同步或通信。双向同步或通信:两个任务相互同步或通信。双向同步不能在任务与ISR之间进行,因为ISR不
2、能等待。概述第4页,共100页,编辑于2022年,星期五2023/1/5TaskxTaskyPOSTPENDISRxTaskyPOSTPENDTaskxTaskyPOSTPENDPOSTPEND任务与任务之间的同步(单向)任务与任务之间的同步(单向)任务与任务之间的同步(单向)任务与任务之间的同步(单向)任务与任务与任务与任务与ISRISR之间的同步(单向)之间的同步(单向)之间的同步(单向)之间的同步(单向)任务与任务之间的同步(双向)任务与任务之间的同步(双向)任务与任务之间的同步(双向)任务与任务之间的同步(双向)第5页,共100页,编辑于2022年,星期五2023/1/6在嵌入式多任务
3、系统中,任务间的耦合程度是不一样的:耦合程度较高:任务之间需要进行大量的通信,相应的系统开销较大;耦合程度较低:任务之间不存在通信需求,其间的同步关系很弱甚至不需要同步或互斥,系统开销较小。研究任务间耦合程度的高低对于合理地设计应用系统、划分任务有很重要的作用。概述第6页,共100页,编辑于2022年,星期五2023/1/7在单处理器平台上,嵌入式操作系统内核提供的同步、互斥与通信机制主要包括:信号量(semaphore),用于互斥与同步事件(组)(event group),用于同步异步信号(asynchronous signal),用于同步邮箱(mailbox)、消息队列(message q
4、ueue)或管道(pipe),用于消息通信概述第7页,共100页,编辑于2022年,星期五2023/1/8以下一些机制也可用于同步与通信(在单处理器或多处理器系统中):全局变量共享内存Sockets远程过程调用(Remote Procedure Call)概述第8页,共100页,编辑于2022年,星期五2023/1/91.信号量信号量的种类及用途互斥信号量二值信号量计数信号量信号量机制的主要数据结构信号量的主要功能第9页,共100页,编辑于2022年,星期五2023/1/10信号量用于实现任务与任务之间、任务与中断处理程序之间的同步与互斥。信号量一般分为三种:用于解决互斥问题的互斥信号量。它比
5、较特殊,可能会引起优先级反转问题。用于解决同步问题的二值信号量。用于解决资源计数问题的计数信号量。将信号量进行种类细分,可以根据其用途,在具体实现时做专门处理,提高执行效率和可靠性。信号量的种类及用途第10页,共100页,编辑于2022年,星期五2023/1/11用互斥信号量保护的代码区称作“临界区”,临界区代码通常用于对共享资源的访问。互斥信号量的值被初始化成1,表明目前没有任务进入“临界区”,但最多只有一个任务可以进入“临界区”。第一个试图进入“临界区”的任务将成功获得互斥信号量,而随后试图进入用同一信号量保护的临界区的所有其他任务就必须等待。当任务离开“临界区”时,它将释放信号量并允许正
6、在等待该信号量的任务进入“临界区”。互斥信号量Task1Task2共享资源共享资源第11页,共100页,编辑于2022年,星期五2023/1/13二值信号量二值信号量主要用于任务与任务之间、任务与中断服务程序之间的同步用于同步的二值信号量初始值为0,表示同步事件尚未产生;任务申请信号量以等待该同步事件的发生;另一个任务或ISR到达同步点时,释放信号量(将其值设置为1)表示同步事件已发生,以唤醒等待的任务。第13页,共100页,编辑于2022年,星期五2023/1/14二值信号量availableunavailableacquire(value=0)release(value=1)Initial
7、value=0二值信号量状态图二值信号量状态图第14页,共100页,编辑于2022年,星期五2023/1/15Task1()执行一些操作执行一些操作;将信号量将信号量sem1置置1;申请信号量申请信号量sem2;Task2()申请信号量申请信号量sem1;执行一些操作执行一些操作;将信号量将信号量sem2置置1;Task2申申 请请 信信 号号 量量sem1失失败败,系系统统切切换到换到Task1sem1被被 置置1后后,Task2得到得到sem1并抢占并抢占Task1Task2运运行行到到某某处处时时因因某某种种原原因因被被阻阻塞塞,系系 统统 切切 换换 到到Task1用二值信号量实现两个
8、任务之间的双向同步用二值信号量实现两个任务之间的双向同步用二值信号量实现两个任务之间的双向同步用二值信号量实现两个任务之间的双向同步 Task2Task2优先级高于优先级高于优先级高于优先级高于Task1Task1 sem1sem1和和和和sem2sem2的初始值均为的初始值均为的初始值均为的初始值均为0 0第15页,共100页,编辑于2022年,星期五2023/1/16计数信号量计数信号量用于控制系统中共享资源的多个计数信号量用于控制系统中共享资源的多个实例的使用,允许多个任务同时访问同一种实例的使用,允许多个任务同时访问同一种资源的多个实例资源的多个实例计数信号量被初始化为计数信号量被初始
9、化为n(非负整数),(非负整数),n为该为该种共享资源的数目。种共享资源的数目。Task1Task2共享资源实例共享资源实例nTaskm共享资源实例共享资源实例1第16页,共100页,编辑于2022年,星期五2023/1/17计数信号量availableunavailableInitialcount0acquire(count=0)release(count=1)Initialcount=0计数信号量状态图计数信号量状态图acquire(count=count-1)release(count=count+1)第17页,共100页,编辑于2022年,星期五2023/1/20信号量机制的主要数据结
10、构信号量控制块:管理所有创建的信号量,内核在系统运行时动态分配和回收信号量控制块互斥和二值信号量控制块结构:Binary_Semaphore_Control_Blockwait_queue任务等待队列任务等待队列attributes信号量属性信号量属性wait_discipline任务等待信号量的方式任务等待信号量的方式priority_ceiling优先级天花板值优先级天花板值lock是否被占有是否被占有holder拥有者拥有者 count当前计数值当前计数值第20页,共100页,编辑于2022年,星期五2023/1/21信号量内部实现机制实例说明C/OS-II事件控制块ECB同步与通信机制
11、的基本数据结构typedef structINT8UOSEventType;/事件类型INT8UOSEventGrp;/等待任务所在的组INT16UOSEventCnt;/计数器(信号量)void*OSEventPtr;/指向消息或消息队列的指针INT8UOSEventTblOS_EVENT_TBL_SIZE;/等待任务列表OS_EVENT;第21页,共100页,编辑于2022年,星期五2023/1/22信号量内部实现机制实例说明C/OS-II当一个事件发生后,等待事件列表中优先级最高的任务(即在.OSEventTbl&OSEventGrp中所有被置1的位中优先级数值最小的任务)得到该事件。第
12、22页,共100页,编辑于2022年,星期五2023/1/23信号量内部实现机制实例说明C/OS-II当.OSEventTbln中的任何一位为1时,OSEventGrp中的第n位为1。与任务就绪列表类似!第23页,共100页,编辑于2022年,星期五2023/1/24信号量内部实现机制实例说明C/OS-II将一个任务插入到等待事件的任务列表中:pevent-OSEventGrp|=OSMapTblprio 3;pevent-OSEventTblprio 3|=OSMapTblprio&0 x07;与将一个任务插入到就绪列表中的操作类似!IndexBitmask(Binary)0 0000000
13、11 000000102 000001003 000010004 000100005 001000006 010000007 10000000第24页,共100页,编辑于2022年,星期五2023/1/25信号量内部实现机制实例说明C/OS-II从等待事件的任务列表中使任务脱离等待状态if(pevent-OSEventTblprio 3&=OSMapTblprio&0 x07)=0)pevent-OSEventGrp&=OSMapTblprio 3;与将任务从就绪列表中清除的操作类似!第25页,共100页,编辑于2022年,星期五2023/1/26信号量内部实现机制实例说明C/OS-II在等待
14、事件的任务列表中查找优先级最高的任务y=OSUnMapTblpevent-OSEventGrp;x=OSUnMapTblpevent-OSEventTbly;prio=(y 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);/调用者需检查返
15、回值,如果为NULL则表示建立失败第32页,共100页,编辑于2022年,星期五2023/1/33获取(申请)信号量功能:试图获得应用指定的信号量。if 信号量的值大于0then 将信号量的值减1else 根据接收信号量的选项,将任务放到等待队列中,或是直接返回第33页,共100页,编辑于2022年,星期五2023/1/34获取(申请)信号量当所申请的信号量不能被立即获得时,可以有以下几种选择:永远等待 不等待,立即返回,并返回一个错误状态码指定等待时限(可有效避免死锁)注意:不允许在ISR中选择等待当任务选择等待时,将被按FIFO或优先级顺序放置在等待队列中第34页,共100页,编辑于202
16、2年,星期五2023/1/35获取(申请)信号量如果任务等待一个使用优先级继承算法的互斥信号量,且它的优先级高于当前正占有此信号量的任务的优先级,那么占有信号量的任务将继承这个被阻塞的任务的优先级。如果任务成功地获得一个采用优先级天花板算法的互斥信号量,它的优先级又低于优先级天花板,那么它的优先级将被抬升至天花板。第35页,共100页,编辑于2022年,星期五2023/1/36获取(等待)一个信号量OSSemPend()void OSSemPend(OS_EVENT*pevent,INT16U timeout,INT8U*err)if(pevent-OSEventCnt 0)/信号量值大于0,
17、成功获得信号量并返回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=
18、OS_TIMEOUT;return;OSTCBCur-OSTCBEventPtr=(OS_EVENT*)0;*err=OS_NO_ERR;/任务由于获得信号量而恢复执行,本调用成功返回第36页,共100页,编辑于2022年,星期五2023/1/37获取(无等待地请求)一个信号量OSSemAccept()INT16U OSSemAccept(OS_EVENT*pevent)INT16U cnt;cnt=pevent-OSEventCnt;if(cnt 0)pevent-OSEventCnt-;return(cnt);注意:即使不能成功获得信号量(返回值为注意:即使不能成功获得信号量(返回值为0)
19、,调用),调用者也不会被阻塞。此函数可以在中断处理程序中使用。者也不会被阻塞。此函数可以在中断处理程序中使用。第37页,共100页,编辑于2022年,星期五2023/1/38释放信号量功能:释放一个应用指定的信号量。if 没有任务等待这个信号量then 信号量的值加1 else 将信号量分配给一个等待任务(将相应的任务移出等待队列,使其就绪)如果使用了优先级继承或优先级天花板算法,那么执行该功能(系统调用)的任务的优先级将恢复到原来的高度。第38页,共100页,编辑于2022年,星期五2023/1/39释放一个信号量OSSemPost()INT8U OSSemPost(OS_EVENT*pev
20、ent)if(pevent-OSEventGrp!=0 x00)/如果有任务在等待该信号量OS_EventTaskRdy(pevent,(void*)0,OS_STAT_SEM);/使等待任务列表中优先级最高的任务就绪OS_Sched();/内核实施任务调度return(OS_NO_ERR);/成功返回 if(pevent-OSEventCnt OSEventCnt+;/信号量的值加1return(OS_NO_ERR);/成功返回 return(OS_SEM_OVF);/信号量溢出第39页,共100页,编辑于2022年,星期五2023/1/40删除信号量功能:从系统中删除应用指定的一个信号量内
21、核动作:将信号量控制块返还给系统删除信号量的不一定是创建信号量的任务如果有任务正在等待获得该信号量,执行此功能将使所有等待这个信号量的任务回到就绪队列中,且返回一个状态码指示该信号量已被删除第40页,共100页,编辑于2022年,星期五2023/1/41删除一个信号量OSSemDel()OS_EVENT*OSSemDel(OS_EVENT*pevent,INT8U opt,INT8U*err)BOOLEAN tasks_waiting;if(pevent-OSEventGrp!=0 x00/根据是否有任务在等待信号量设置等待标志tasks_waiting=TRUE;elsetasks_wait
22、ing=FALSE;switch(opt)case OS_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);第4
23、1页,共100页,编辑于2022年,星期五2023/1/42删除一个信号量OSSemDel()case OS_DEL_ALWAYS:/无论有无任务等待都删除信号量/将等待列表中的每个任务都设置成就绪while(pevent-OSEventGrp!=0 x00)OS_EventTaskRdy(pevent,(void*)0,OS_STAT_SEM);/释放该信号量的ECB回空闲控制块链pevent-OSEventType=OS_EVENT_TYPE_UNUSED;pevent-OSEventFreeList;OSEventFreeList=pevent;/如果之前有任务等待信号量,内核实施任务调
24、度if(tasks_waiting=TRUE)OS_Sched();*err=OS_NO_ERR;return(OS_EVENT*)0);default:*err=OS_ERR_INVALID_OPT;return(pevent);第42页,共100页,编辑于2022年,星期五2023/1/432.邮箱和消息队列概述消息队列机制的主要数据结构消息队列的主要功能第43页,共100页,编辑于2022年,星期五2023/1/44任务间的通信方式直接通信。在通信过程中双方必须明确地知道(命名)彼此:wSend(P,message)发送一个消息到任务PwReceive(Q,message)从任务Q接收一
25、个消息 间接通信。通信双方不需要指出消息的来源或去向,而通过中间机制来通信。如:wsend(A,message)发送一个消息给邮箱Awreceive(A,message)从邮箱A接收一个消息概述第44页,共100页,编辑于2022年,星期五2023/1/45消息队列:属于间接通信方式消息:内存空间中一段长度可变的缓冲区,其长度和内容均可以由用户定义,其内容可以是实际的数据、数据块的指针或空。对消息内容的解释由应用完成。从操作系统观点看,消息没有定义的格式,所有的消息都是字节流,没有特定的含义。从应用观点看,根据应用定义的消息格式,消息被解释成特定的含义。应用可以只把消息当成一个标志,这时消息机
26、制用于实现同步概述第45页,共100页,编辑于2022年,星期五2023/1/46一些操作系统内核把消息进一步分为:邮箱和消息队列邮箱仅能存放单条消息,它提供了一种低开销的机制来传送信息。每个邮箱可以保存一条大小为若干个字节的消息。消息队列可存放若干消息,提供了一种任务间缓冲通信的方法。消息机制可支持定长与可变长度两种模式的消息,可变长度的消息队列需要对队列中的每一条消息增加额外的存储开销。概述第46页,共100页,编辑于2022年,星期五2023/1/47消息队列机制的主要数据结构消息队列控制块管理所有创建的消息队列,系统运行时动态分配和回收消息队列控制块消息队列缓冲区存放发送到该队列的消息
27、,接收者从缓冲区中取出消息。消息的发送或接收有两种方法(影响消息缓冲区结构):w将数据从发送任务的空间完全拷贝到接收任务的空间中(效率较低,执行时间与消息大小有关)w只传递指向数据存储空间的指针(提高系统性能)第47页,共100页,编辑于2022年,星期五2023/1/48SendingTaskReceivingTaskMessage1Message1Message1发送任务的发送任务的内存区域内存区域消息队列的消息队列的内存区域内存区域接收任务的接收任务的内存区域内存区域1stcopy2ndcopy发送和接收消息的消息拷贝和内存使用发送和接收消息的消息拷贝和内存使用发送和接收消息的消息拷贝和
28、内存使用发送和接收消息的消息拷贝和内存使用 这种消息传递方法效率低、占用空间大这种消息传递方法效率低、占用空间大这种消息传递方法效率低、占用空间大这种消息传递方法效率低、占用空间大 一种效率更高的方式是传递消息指针一种效率更高的方式是传递消息指针一种效率更高的方式是传递消息指针一种效率更高的方式是传递消息指针第48页,共100页,编辑于2022年,星期五2023/1/49number_of_messagemax_message_countnumber_of_messagemax_message_sizewait_disciplinewait_queuequeue_startqueue_inqu
29、eue_outqueue_endmessagemessagemessagemessagemessagemessagemessagemessagemessagemax_message_count消息队列控消息队列控制块制块消息队列缓消息队列缓冲区冲区消息队列机制的主要数据结构第49页,共100页,编辑于2022年,星期五2023/1/50消息队列的环形缓冲消息队列的环形缓冲消息队列的环形缓冲消息队列的环形缓冲消息队列机制的主要数据结构第50页,共100页,编辑于2022年,星期五2023/1/51消息队列的主要功能创建消息队列发送普通消息发送紧急消息发送广播消息接收消息删除消息队列获取有关消息队
30、列的各种信息 第51页,共100页,编辑于2022年,星期五2023/1/52消息队列的主要功能随着任务(或ISR)不断地向(从)消息队列发送(接收)消息,消息队列的状态不断转换,可以有如下几种状态:消息队列为空消息队列为空且有任务等待接收消息消息队列中有消息,但未满消息队列满 消息队列满,且有任务等待向它发送消息 第52页,共100页,编辑于2022年,星期五2023/1/53创建消息队列创建消息队列时,调用者可以指定如下参数:消息的最大长度每个消息队列中最多的消息数消息队列的属性w任务等待消息时的排队方式:FIFO或PRIORITY系统为新创建的消息队列分配唯一的ID 第53页,共100页
31、,编辑于2022年,星期五2023/1/54发送消息根据紧急程度的不同,消息通常可分为普通消息与紧急消息。如果有任务正在等待消息(即消息队列为空),则普通消息发送和紧急消息发送的执行效果是一样的。任务从等待队列移到就绪队列中,消息被拷贝到任务提供的缓冲区中(或者由接收任务得到指向消息的指针)。如果没有任务等待,发送普通消息将消息放在队列尾,而发送紧急消息将消息放在队列头。第54页,共100页,编辑于2022年,星期五2023/1/55发送消息Msg3接收任务接收任务等待列表等待列表Msg2Msg1消息队列消息队列发送普通消息先进先出发送普通消息先进先出(FIFO)次序)次序Msg3接收任务接收
32、任务等待列表等待列表Msg2Msg1消息队列消息队列发送紧急消息后进先出发送紧急消息后进先出(LIFO)次序)次序第55页,共100页,编辑于2022年,星期五2023/1/56发送消息如果发送消息时队列已被填满,则不同的操作系统可能采取不同的处理办法:挂起试图向已满的消息队列中发送消息的任务(不适用于中断服务程序)简单地丢弃该条消息并向调用者返回错误信息广播消息。在此之前所有试图从队列中接收消息的任务此时都将获得相同的消息。该功能拷贝消息到各任务的消息缓冲中(或者让所有的等待任务得到指向消息的指针),并唤醒所有的等待任务。第56页,共100页,编辑于2022年,星期五2023/1/57接收消
33、息如果指定的消息队列中有消息,则将其中的第一条消息拷贝到调用者的缓冲区(或者将第一条消息指针传递给调用者),并从消息队列中删除它。如果此时消息队列中没有消息,则可能出现以下几种情况:永远等待消息的到达:等待消息的任务按FIFO或优先级高低顺序排列在等待队列中 等待消息且指定等待时限:等待消息的任务按FIFO或优先级高低顺序排列在等待队列中不等待,强制立即返回第57页,共100页,编辑于2022年,星期五2023/1/58接收消息限时等待可有效预防死锁中断服务程序接收消息时必须选择不等待,因为中断服务程序是不能被阻塞的。如果消息队列被应用删除,则所有等待该消息队列的任务都被返回一个错误信息,并回
34、复到就绪状态。第58页,共100页,编辑于2022年,星期五2023/1/59接收消息Task4High消息队列消息队列接收任务等待列表接收任务等待列表任务等待列表基于任务等待列表基于优先级的次序优先级的次序Task2mediumTask3mediumTask1LowTask4High消息队列消息队列接收任务等待列表接收任务等待列表任务等待列表先进先出任务等待列表先进先出(FIFO)次序)次序Task2mediumTask3mediumTask1Low第59页,共100页,编辑于2022年,星期五2023/1/60删除消息队列从系统中删除指定的消息队列,释放消息队列控制块及消息队列缓冲区。任何
35、知道此消息队列ID号的代码都可以删除它。消息队列被删除后,所有等待从这个消息队列接收消息的任务都回到就绪态,并得到一个错误信息表明消息队列已被删除。第60页,共100页,编辑于2022年,星期五2023/1/613.事 件概述事件机制的主要数据结构事件的主要功能第61页,共100页,编辑于2022年,星期五2023/1/62在嵌入式实时内核中,事件是指一种表明预先定义的系统事件已经发生的机制。事件机制用于任务与任务之间、任务与ISR之间的同步。其主要的特点是可实现一对多的同步。一个事件就是一个标志,不具备其它信息。一个或多个事件构成一个事件集。事件集可以用一个指定长度的变量(比如一个32位的无
36、符号整型变量,不同的操作系统其具体实现不一样)来表示,而每个事件由在事件集变量中的某一位来代表。概述第62页,共100页,编辑于2022年,星期五2023/1/63事件及事件集有以下特点:事件间相互独立事件仅用于同步,不提供数据传输功能事件无队列,即多次发送同一事件,在未经过任何处理的情况下,其效果等同于只发送一次。提供事件机制的意义在于:当某任务要与多个任务或中断服务同步时,就需要使用事件机制。若任务需要与一组事件中的任意一个发生同步,可称为独立型同步(逻辑“或”关系)。任务也可以等待若干事件都发生时才同步,称为关联型同步(逻辑“与”关系)。概述第63页,共100页,编辑于2022年,星期五
37、2023/1/64“或或或或”同步和同步和同步和同步和“与与与与”同步同步同步同步概述概述第64页,共100页,编辑于2022年,星期五2023/1/65用多个事件的组合发信号给多个任务用多个事件的组合发信号给多个任务用多个事件的组合发信号给多个任务用多个事件的组合发信号给多个任务概述概述第65页,共100页,编辑于2022年,星期五2023/1/66术语:发送事件集。指在一次发送过程中发往接收者(比如任务)的一个或多个事件的组合。待处理事件集。指已被发送到一个接收者但还没有被接收(即正在等待处理)的所有事件的集合。事件条件。指事件接收者在一次接收过程中期待接收的一个或多个事件的集合。w“或”
38、同步:待处理事件集只要包括事件条件中的任一事件即可满足要求;w“与”同步:其二是待处理事件集必须包括事件条件中的全部事件方可满足要求。概述概述第66页,共100页,编辑于2022年,星期五2023/1/67事件机制的主要数据结构事件集控制块:管理所有创建的事件集或者事件集附属于任务,不需创建,其相关参数成为任务控制块的一部分第67页,共100页,编辑于2022年,星期五2023/1/68事件的内部实现机制实例说明C/OS-II事件标志组数据结构typedef structINT8UOSFlagType;/指示本数据结构的类型void*OSFlagWaitList;/等待事件标志的任务链表OS_
39、FLAGSOSFlagFlags;/各事件标志的当前状态OS_FLAG_GRP;事件标志节点数据结构typedef structvoid*OSFlagNodeNext;/后驱指针void*OSFlagNodePrev;/前驱指针void*OSFlagNodeTCB;/任务控制块指针void*OSFlagNodeFlagGrp;/指回OS_FLAG_GRP结构OS_FLAGSOSFlagNodeFlags;/所等待的事件标志组合INT8U OSFlagNodeWaitType;/等待类型(与、或)OS_FLAG_NODE;第68页,共100页,编辑于2022年,星期五2023/1/69事件标志组
40、、事件标志节点及任务控制块之间的关系第69页,共100页,编辑于2022年,星期五2023/1/70事件的主要功能创建事件集删除事件集发送事件(集)接收事件(集)获取有关事件集的各种信息 第70页,共100页,编辑于2022年,星期五2023/1/71创建事件集申请空闲事件集控制块,设置事件集属性,初始化控制块中的域,分配ID号第71页,共100页,编辑于2022年,星期五2023/1/72创建一个事件标志组OSFlagCreate()OS_FLAG_GRP *OSFlagCreate(OS_FLAGS flags,INT8U*err)OS_FLAG_GRP *pgrp;pgrp=OSFlag
41、FreeList;/获取一个空闲事件标志组结构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(pgr
42、p);第72页,共100页,编辑于2022年,星期五2023/1/73接收事件(集)在接收事件(集)时可以有如下选项,每一类只能选择其一:接收事件(集)时可等待(WAIT)w接收者永远等待,直到事件条件被满足后成功返回;w接收者根据指定的时限等待。接收事件(集)时不等待(NO_WAIT)待处理事件集必须包含事件条件中的全部事件方可满足要求(EVENT_ALL),即按照“与”条件接收事件待处理事件集只要包含事件条件中的任一事件即可满足要求(EVENT_ANY),即按照“或”条件接收事件第73页,共100页,编辑于2022年,星期五2023/1/74接收(等待)事件标志组的事件标志位OSFlagP
43、end()OS_FLAGS OSFlagPend(OS_FLAG_GRP*pgrp,OS_FLAGS flags,INT8U wait_type,INT16U timeout,INT8U*err)OS_FLAG_NODE node;/OS_FLAG_NODE作为局部变量存在于调用该函数的任务堆栈中OS_FLAGS flags_cur;OS_FLAGS flags_rdy;switch(wait_type)case OS_FLAG_WAIT_SET_ALL:/任务以“与”方式等待事件标志flags_rdy=pgrp-OSFlagFlags&flags;if(flags_rdy=flags)/事件
44、标志当前状态与等待条件相符pgrp-OSFlagFlags&=flags_rdy;/清除(即“消费”)满足条件的事件标志flags_cur=pgrp-OSFlagFlags;*err=OS_NO_ERR;return(flags_cur);/返回处理后的事件标志组elseOS_FlagBlock(pgrp,&node,flags,wait_type,timeout);/事件标志当前状态与等待条件不相符,任务被阻塞break;第74页,共100页,编辑于2022年,星期五2023/1/75接收(等待)事件标志组的事件标志位OSFlagPend()case OS_FLAG_WAIT_SET_ANY
45、:/任务以“或”方式等待事件标志 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);/返回处理后的事件标志组elseOS_FlagBlock(pgrp,&node,flags,wait_type,timeout);/事件标志当前状态与等待条件不相符,任务被阻塞break;default:fl
46、ags_cur=(OS_FLAGS)0;*err=OS_FLAG_ERR_WAIT_TYPE;return(flags_cur);第75页,共100页,编辑于2022年,星期五2023/1/76OS_Sched();/当前任务被放到事件标志等待链后,内核实施任务调度if(OSTCBCur-OSTCBStat&OS_STAT_FLAG)/判断任务重新就绪的原因,如果是等待超时OS_FlagUnlink(&node);/将任务从事件标志等待链中解除下来OSTCBCur-OSTCBStat=OS_STAT_RDY;/设置当前任务状态为就绪flags_cur=(OS_FLAGS)0;/无效的事件标志状
47、态*err=OS_TIMEOUT;/超时信号else/任务重新就绪的原因是在限定时间得到了满足条件的事件标志pgrp-OSFlagFlags&=OSTCBCur-OSTCBFlagsRdy;/清除(即“消费”)满足条件的事件标志flags_cur=pgrp-OSFlagFlags;*err=OS_NO_ERR;return(flags_cur);接收(等待)事件标志组的事件标志位OSFlagPend()第76页,共100页,编辑于2022年,星期五2023/1/77添加一个任务到事件标志组等待任务链表中OS_FlagBlock()第77页,共100页,编辑于2022年,星期五2023/1/78
48、接收(无等待地获取)事件标志OSFlagAccept()OS_FLAGS OSFlagAccept(OS_FLAG_GRP*pgrp,OS_FLAGS flags,INT8U wait_type,INT8U*err)OS_FLAGS flags_cur,flags_rdy;*err=OS_NO_ERR;switch(wait_type)/判断等待事件标志的方式 case OS_FLAG_WAIT_SET_ALL:/”与”方式等待flags_rdy=pgrp-OSFlagFlags&flags;if(flags_rdy=flags)pgrp-OSFlagFlags&=flags_rdy;/事件标
49、志当前状态与等待条件相符,清除(即“消费”)相应的事件标志else *err =OS_FLAG_ERR_NOT_RDY;/不符合条件,返回错误信息flags_cur=pgrp-OSFlagFlags;break;第78页,共100页,编辑于2022年,星期五2023/1/79接收(无等待地获取)事件标志OSFlagAccept()case OS_FLAG_WAIT_SET_ANY:/”或”方式等待flags_rdy=pgrp-OSFlagFlags&flags;if(flags_rdy!=(OS_FLAGS)0)pgrp-OSFlagFlags&=flags_rdy;/事件标志当前状态与等待条
50、件相符,清除(即“消费”)相应的事件标志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);第79页,共100页,编辑于2022年,星期五2023/1/80发送事件(集)调用者(任务或中断)构造一个事件(集),将其发往接收者(比如目标任务)。可能会出现以下几种情况之一:目标任务正在等待的事件条