同步互斥与 通信_第1页
同步互斥与 通信_第2页
同步互斥与 通信_第3页
同步互斥与 通信_第4页
同步互斥与 通信_第5页
已阅读5页,还剩92页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

同步互斥与通信第一页,共一百页,编辑于2023年,星期二2023/6/82主要内容信号量邮箱和消息队列事件异步信号*第二页,共一百页,编辑于2023年,星期二2023/6/83概述多任务系统中任务之间的关系相互独立仅竞争CPU资源竞争除CPU外的其他资源(互斥)同步协调彼此运行的步调通信彼此间传递数据或信息,以协同完成某项工作第三页,共一百页,编辑于2023年,星期二2023/6/84任务能以以下方式与中断处理程序或其他任务进行同步或通信:单向同步或通信:一个任务与另一个任务或一个ISR同步或通信。双向同步或通信:两个任务相互同步或通信。双向同步不能在任务与ISR之间进行,因为ISR不能等待。概述第四页,共一百页,编辑于2023年,星期二2023/6/85TaskxTaskyPOSTPENDISRxTaskyPOSTPENDTaskxTaskyPOSTPENDPOSTPEND任务与任务之间的同步(单向)任务与ISR之间的同步(单向)任务与任务之间的同步(双向)第五页,共一百页,编辑于2023年,星期二2023/6/86在嵌入式多任务系统中,任务间的耦合程度是不一样的:耦合程度较高:任务之间需要进行大量的通信,相应的系统开销较大;耦合程度较低:任务之间不存在通信需求,其间的同步关系很弱甚至不需要同步或互斥,系统开销较小。研究任务间耦合程度的高低对于合理地设计应用系统、划分任务有很重要的作用。概述第六页,共一百页,编辑于2023年,星期二2023/6/87在单处理器平台上,嵌入式操作系统内核提供的同步、互斥与通信机制主要包括:信号量(semaphore),用于互斥与同步事件(组)(eventgroup),用于同步异步信号(asynchronoussignal),用于同步邮箱(mailbox)、消息队列(messagequeue)或管道(pipe),用于消息通信概述第七页,共一百页,编辑于2023年,星期二2023/6/88以下一些机制也可用于同步与通信(在单处理器或多处理器系统中):全局变量共享内存Sockets远程过程调用(RemoteProcedureCall)概述第八页,共一百页,编辑于2023年,星期二2023/6/891.信号量信号量的种类及用途互斥信号量二值信号量计数信号量信号量机制的主要数据结构信号量的主要功能第九页,共一百页,编辑于2023年,星期二2023/6/810信号量用于实现任务与任务之间、任务与中断处理程序之间的同步与互斥。信号量一般分为三种:用于解决互斥问题的互斥信号量。它比较特殊,可能会引起优先级反转问题。用于解决同步问题的二值信号量。用于解决资源计数问题的计数信号量。将信号量进行种类细分,可以根据其用途,在具体实现时做专门处理,提高执行效率和可靠性。信号量的种类及用途第十页,共一百页,编辑于2023年,星期二2023/6/811用互斥信号量保护的代码区称作“临界区”,临界区代码通常用于对共享资源的访问。互斥信号量的值被初始化成1,表明目前没有任务进入“临界区”,但最多只有一个任务可以进入“临界区”。第一个试图进入“临界区”的任务将成功获得互斥信号量,而随后试图进入用同一信号量保护的临界区的所有其他任务就必须等待。当任务离开“临界区”时,它将释放信号量并允许正在等待该信号量的任务进入“临界区”。互斥信号量Task1Task2共享资源第十一页,共一百页,编辑于2023年,星期二2023/6/812各种互斥机制比较比较项目关中断使用测试并置位指令禁止任务切换使用信号量锁定范围互斥力度最强,锁定所有外部可屏蔽中断,凡是以中断形式到达的外部事件以及与之相关联的任务或处理过程均得不到执行凡是使用该指令访问共享资源的代码所有的任务只影响竞争共享资源的任务对系统响应时间的影响如果关中断的时间较长,对系统的响应性能有很大影响较小如果禁止切换的时间过长,则影响系统的响应性能对系统响应性能有一定影响,可能导致优先级反转实现时的系统开销小小小较大注意事项关中断时间要尽量短不是所有的处理器都具备这种指令,影响可移植性关调度的时间要尽量短需采用一定的策略解决优先级反转问题第十二页,共一百页,编辑于2023年,星期二2023/6/813二值信号量二值信号量主要用于任务与任务之间、任务与中断服务程序之间的同步用于同步的二值信号量初始值为0,表示同步事件尚未产生;任务申请信号量以等待该同步事件的发生;另一个任务或ISR到达同步点时,释放信号量(将其值设置为1)表示同步事件已发生,以唤醒等待的任务。第十三页,共一百页,编辑于2023年,星期二2023/6/814二值信号量availableunavailableacquire(value=0)release(value=1)Initialvalue=0二值信号量状态图第十四页,共一百页,编辑于2023年,星期二2023/6/815Task1(){……

执行一些操作;

将信号量sem1置1;

申请信号量sem2;…………}Task2(){……

申请信号量sem1;

执行一些操作;

将信号量sem2置1;…………}Task2申请信号量sem1失败,系统切换到Task1sem1被置1后,Task2得到sem1并抢占Task1Task2运行到某处时因某种原因被阻塞,系统切换到Task1用二值信号量实现两个任务之间的双向同步Task2优先级高于Task1sem1和sem2的初始值均为0第十五页,共一百页,编辑于2023年,星期二2023/6/816计数信号量计数信号量用于控制系统中共享资源的多个实例的使用,允许多个任务同时访问同一种资源的多个实例计数信号量被初始化为n(非负整数),n为该种共享资源的数目。Task1Task2共享资源实例nTaskm共享资源实例1…………第十六页,共一百页,编辑于2023年,星期二2023/6/817计数信号量availableunavailableInitialcount>0acquire(count=0)release(count=1)Initialcount=0计数信号量状态图acquire(count=count-1)release(count=count+1)第十七页,共一百页,编辑于2023年,星期二2023/6/818计数信号量

1234…………n生产者任务消费者任务计数信号量使用实例:有界缓冲问题第十八页,共一百页,编辑于2023年,星期二2023/6/819生产者任务do{…产生一个数据项…申请empty申请mutex…将新生成的数据项添加到缓冲中…释放mutex释放full}while(1);消费者任务do{申请full申请mutex…从缓冲中移出一个数据项的内容…释放mutex释放empty…消费新获得的数据项内容…}while(1);计数信号量full:已被填充的数据项数目,取值范围0-n,初始值为0计数信号量empty:空闲数据项数目,取值范围为0-n,初始值为n;互斥信号量mutex:控制生产者任务和消费者任务对有界缓冲的访问,初始值为1。第十九页,共一百页,编辑于2023年,星期二2023/6/820信号量机制的主要数据结构信号量控制块:管理所有创建的信号量,内核在系统运行时动态分配和回收信号量控制块互斥和二值信号量控制块结构:Binary_Semaphore_Control_Blockwait_queue 任务等待队列attributes 信号量属性

wait_discipline 任务等待信号量的方式

priority_ceiling 优先级天花板值lock 是否被占有holder 拥有者

count 当前计数值第二十页,共一百页,编辑于2023年,星期二2023/6/821信号量内部实现机制实例说明

-µC/OS-II事件控制块ECB-同步与通信机制的基本数据结构typedefstruct{INT8U OSEventType;//事件类型INT8U OSEventGrp;//等待任务所在的组INT16U OSEventCnt;//计数器(信号量)void *OSEventPtr;//指向消息或消息队列的指针INT8U OSEventTbl[OS_EVENT_TBL_SIZE];//等待任务列表}OS_EVENT;第二十一页,共一百页,编辑于2023年,星期二2023/6/822信号量内部实现机制实例说明

-µC/OS-II当一个事件发生后,等待事件列表中优先级最高的任务(即在.OSEventTbl[]&OSEventGrp中所有被置1的位中优先级数值最小的任务)得到该事件。第二十二页,共一百页,编辑于2023年,星期二2023/6/823信号量内部实现机制实例说明

-µC/OS-II当.OSEventTbl[n]中的任何一位为1时,OSEventGrp中的第n位为1。与任务就绪列表类似!第二十三页,共一百页,编辑于2023年,星期二2023/6/824信号量内部实现机制实例说明

-µ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第二十四页,共一百页,编辑于2023年,星期二2023/6/825信号量内部实现机制实例说明

-µC/OS-II从等待事件的任务列表中使任务脱离等待状态if((pevent->OSEventTbl[prio>>3]&=~OSMapTbl[prio&0x07])==0){pevent->OSEventGrp&=~OSMapTbl[prio>>3];}与将任务从就绪列表中清除的操作类似!第二十五页,共一百页,编辑于2023年,星期二2023/6/826信号量内部实现机制实例说明

-µC/OS-II在等待事件的任务列表中查找优先级最高的任务y=OSUnMapTbl[pevent->OSEventGrp];x=OSUnMapTbl[pevent->OSEventTbl[y]];prio=(y<<3)+x;与查找优先级最高的就绪任务的操作类似!第二十六页,共一百页,编辑于2023年,星期二2023/6/827信号量内部实现机制实例说明

-µC/OS-II空闲事件控制块链表第二十七页,共一百页,编辑于2023年,星期二2023/6/828信号量的主要功能创建信号量获取(申请)信号量释放信号量删除信号量获取有关信号量的各种信息第二十八页,共一百页,编辑于2023年,星期二2023/6/829创建信号量功能:根据应用传递的参数创建一个信号量参数:信号量的名字、属性和初始值等。内核动作:从空闲信号量控制块链中分配一个信号量控制块,并初始化信号量属性。创建成功时,为其分配唯一的ID号返回给应用。如果已创建信号量数量已达到用户配置的最大数量,就返回错误。第二十九页,共一百页,编辑于2023年,星期二2023/6/830创建信号量信号量的属性包括其类型、任务等待信号量的方式(即排列的顺序)、解决优先级反转的策略。信号量的类型互斥信号量(MUTEX_SEMAPHORE)计数信号量(COUNTING_SEMAPHORE)二值信号量(BINARY_SEMAPHORE)第三十页,共一百页,编辑于2023年,星期二2023/6/831创建信号量任务等待信号量的方式

先进先出(FIFO)顺序优先级(PRIORITY)顺序优先级反转问题的解决方法(只适用于互斥信号量)优先级继承算法(INHERIT_PRIORITY)优先级天花板算法(PRIORITY_CEILING),需给出所有可能获得此信号量的任务中优先级最高的任务的优先级。第三十一页,共一百页,编辑于2023年,星期二2023/6/832创建一个信号量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则表示建立失败}第三十二页,共一百页,编辑于2023年,星期二2023/6/833获取(申请)信号量功能:试图获得应用指定的信号量。if 信号量的值大于0then 将信号量的值减1else 根据接收信号量的选项,将任务放到等待队列中,或是直接返回第三十三页,共一百页,编辑于2023年,星期二2023/6/834获取(申请)信号量当所申请的信号量不能被立即获得时,可以有以下几种选择:永远等待不等待,立即返回,并返回一个错误状态码指定等待时限(可有效避免死锁)注意:不允许在ISR中选择等待当任务选择等待时,将被按FIFO或优先级顺序放置在等待队列中第三十四页,共一百页,编辑于2023年,星期二2023/6/835获取(申请)信号量如果任务等待一个使用优先级继承算法的互斥信号量,且它的优先级高于当前正占有此信号量的任务的优先级,那么占有信号量的任务将继承这个被阻塞的任务的优先级。如果任务成功地获得一个采用优先级天花板算法的互斥信号量,它的优先级又低于优先级天花板,那么它的优先级将被抬升至天花板。

第三十五页,共一百页,编辑于2023年,星期二2023/6/836获取(等待)一个信号量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;//任务由于获得信号量而恢复执行,本调用成功返回}第三十六页,共一百页,编辑于2023年,星期二2023/6/837获取(无等待地请求)一个信号量OSSemAccept()INT16UOSSemAccept(OS_EVENT*pevent){ INT16Ucnt; cnt=pevent->OSEventCnt; if(cnt>0){ pevent->OSEventCnt--; } return(cnt);}注意:即使不能成功获得信号量(返回值为0),调用者也不会被阻塞。此函数可以在中断处理程序中使用。第三十七页,共一百页,编辑于2023年,星期二2023/6/838释放信号量功能:释放一个应用指定的信号量。if 没有任务等待这个信号量then 信号量的值加1else 将信号量分配给一个等待任务(将相应的任务移出等待队列,使其就绪)

如果使用了优先级继承或优先级天花板算法,那么执行该功能(系统调用)的任务的优先级将恢复到原来的高度。第三十八页,共一百页,编辑于2023年,星期二2023/6/839释放一个信号量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);//信号量溢出}第三十九页,共一百页,编辑于2023年,星期二2023/6/840删除信号量功能:从系统中删除应用指定的一个信号量内核动作:将信号量控制块返还给系统删除信号量的不一定是创建信号量的任务如果有任务正在等待获得该信号量,执行此功能将使所有等待这个信号量的任务回到就绪队列中,且返回一个状态码指示该信号量已被删除第四十页,共一百页,编辑于2023年,星期二2023/6/841删除一个信号量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); }第四十一页,共一百页,编辑于2023年,星期二2023/6/842删除一个信号量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); }}第四十二页,共一百页,编辑于2023年,星期二2023/6/8432.邮箱和消息队列概述消息队列机制的主要数据结构消息队列的主要功能第四十三页,共一百页,编辑于2023年,星期二2023/6/844任务间的通信方式直接通信。在通信过程中双方必须明确地知道(命名)彼此:Send(P,message)–

发送一个消息到任务PReceive(Q,message)–

从任务Q接收一个消息间接通信。通信双方不需要指出消息的来源或去向,而通过中间机制来通信。如:send(A,message)–

发送一个消息给邮箱Areceive(A,message)–

从邮箱A接收一个消息概述第四十四页,共一百页,编辑于2023年,星期二2023/6/845消息队列:属于间接通信方式消息:内存空间中一段长度可变的缓冲区,其长度和内容均可以由用户定义,其内容可以是实际的数据、数据块的指针或空。对消息内容的解释由应用完成。从操作系统观点看,消息没有定义的格式,所有的消息都是字节流,没有特定的含义。从应用观点看,根据应用定义的消息格式,消息被解释成特定的含义。应用可以只把消息当成一个标志,这时消息机制用于实现同步概述第四十五页,共一百页,编辑于2023年,星期二2023/6/846一些操作系统内核把消息进一步分为:邮箱和消息队列邮箱仅能存放单条消息,它提供了一种低开销的机制来传送信息。每个邮箱可以保存一条大小为若干个字节的消息。消息队列可存放若干消息,提供了一种任务间缓冲通信的方法。消息机制可支持定长与可变长度两种模式的消息,可变长度的消息队列需要对队列中的每一条消息增加额外的存储开销。概述第四十六页,共一百页,编辑于2023年,星期二2023/6/847消息队列机制的主要数据结构消息队列控制块管理所有创建的消息队列,系统运行时动态分配和回收消息队列控制块消息队列缓冲区存放发送到该队列的消息,接收者从缓冲区中取出消息。消息的发送或接收有两种方法(影响消息缓冲区结构):将数据从发送任务的空间完全拷贝到接收任务的空间中(效率较低,执行时间与消息大小有关)只传递指向数据存储空间的指针(提高系统性能)第四十七页,共一百页,编辑于2023年,星期二2023/6/848SendingTaskReceivingTaskMessage1Message1Message1发送任务的内存区域消息队列的内存区域接收任务的内存区域1stcopy2ndcopy发送和接收消息的消息拷贝和内存使用这种消息传递方法效率低、占用空间大一种效率更高的方式是传递消息指针第四十八页,共一百页,编辑于2023年,星期二2023/6/849number_of_messagemax_message_countnumber_of_messagemax_message_sizewait_disciplinewait_queuequeue_startqueue_inqueue_outqueue_endmessagemessagemessagemessagemessagemessagemessagemessagemessagemax_message_count消息队列控制块消息队列缓冲区消息队列机制的主要数据结构第四十九页,共一百页,编辑于2023年,星期二2023/6/850消息队列的环形缓冲消息队列机制的主要数据结构第五十页,共一百页,编辑于2023年,星期二2023/6/851消息队列的主要功能创建消息队列发送普通消息发送紧急消息发送广播消息接收消息删除消息队列获取有关消息队列的各种信息第五十一页,共一百页,编辑于2023年,星期二2023/6/852消息队列的主要功能随着任务(或ISR)不断地向(从)消息队列发送(接收)消息,消息队列的状态不断转换,可以有如下几种状态:消息队列为空消息队列为空且有任务等待接收消息消息队列中有消息,但未满消息队列满消息队列满,且有任务等待向它发送消息

第五十二页,共一百页,编辑于2023年,星期二2023/6/853创建消息队列创建消息队列时,调用者可以指定如下参数:消息的最大长度每个消息队列中最多的消息数消息队列的属性任务等待消息时的排队方式:FIFO或PRIORITY系统为新创建的消息队列分配唯一的ID第五十三页,共一百页,编辑于2023年,星期二2023/6/854发送消息根据紧急程度的不同,消息通常可分为普通消息与紧急消息。如果有任务正在等待消息(即消息队列为空),则普通消息发送和紧急消息发送的执行效果是一样的。任务从等待队列移到就绪队列中,消息被拷贝到任务提供的缓冲区中(或者由接收任务得到指向消息的指针)。如果没有任务等待,发送普通消息将消息放在队列尾,而发送紧急消息将消息放在队列头。第五十四页,共一百页,编辑于2023年,星期二2023/6/855发送消息Msg3接收任务等待列表Msg2Msg1消息队列发送普通消息-先进先出(FIFO)次序Msg3接收任务等待列表Msg2Msg1消息队列发送紧急消息-后进先出(LIFO)次序第五十五页,共一百页,编辑于2023年,星期二2023/6/856发送消息如果发送消息时队列已被填满,则不同的操作系统可能采取不同的处理办法:挂起试图向已满的消息队列中发送消息的任务(不适用于中断服务程序)简单地丢弃该条消息并向调用者返回错误信息广播消息。在此之前所有试图从队列中接收消息的任务此时都将获得相同的消息。该功能拷贝消息到各任务的消息缓冲中(或者让所有的等待任务得到指向消息的指针),并唤醒所有的等待任务。第五十六页,共一百页,编辑于2023年,星期二2023/6/857接收消息如果指定的消息队列中有消息,则将其中的第一条消息拷贝到调用者的缓冲区(或者将第一条消息指针传递给调用者),并从消息队列中删除它。如果此时消息队列中没有消息,则可能出现以下几种情况:永远等待消息的到达:等待消息的任务按FIFO或优先级高低顺序排列在等待队列中等待消息且指定等待时限:等待消息的任务按FIFO或优先级高低顺序排列在等待队列中不等待,强制立即返回第五十七页,共一百页,编辑于2023年,星期二2023/6/858接收消息限时等待可有效预防死锁中断服务程序接收消息时必须选择不等待,因为中断服务程序是不能被阻塞的。如果消息队列被应用删除,则所有等待该消息队列的任务都被返回一个错误信息,并回复到就绪状态。第五十八页,共一百页,编辑于2023年,星期二2023/6/859接收消息Task4High消息队列接收任务等待列表任务等待列表-基于优先级的次序Task2mediumTask3mediumTask1LowTask4High消息队列接收任务等待列表任务等待列表-先进先出(FIFO)次序Task2mediumTask3mediumTask1Low第五十九页,共一百页,编辑于2023年,星期二2023/6/860删除消息队列从系统中删除指定的消息队列,释放消息队列控制块及消息队列缓冲区。任何知道此消息队列ID号的代码都可以删除它。消息队列被删除后,所有等待从这个消息队列接收消息的任务都回到就绪态,并得到一个错误信息表明消息队列已被删除。第六十页,共一百页,编辑于2023年,星期二2023/6/8613.事件概述事件机制的主要数据结构事件的主要功能第六十一页,共一百页,编辑于2023年,星期二2023/6/862在嵌入式实时内核中,事件是指一种表明预先定义的系统事件已经发生的机制。事件机制用于任务与任务之间、任务与ISR之间的同步。其主要的特点是可实现一对多的同步。

一个事件就是一个标志,不具备其它信息。一个或多个事件构成一个事件集。事件集可以用一个指定长度的变量(比如一个32位的无符号整型变量,不同的操作系统其具体实现不一样)来表示,而每个事件由在事件集变量中的某一位来代表。概述第六十二页,共一百页,编辑于2023年,星期二2023/6/863事件及事件集有以下特点:事件间相互独立事件仅用于同步,不提供数据传输功能事件无队列,即多次发送同一事件,在未经过任何处理的情况下,其效果等同于只发送一次。提供事件机制的意义在于:当某任务要与多个任务或中断服务同步时,就需要使用事件机制。若任务需要与一组事件中的任意一个发生同步,可称为独立型同步(逻辑“或”关系)。任务也可以等待若干事件都发生时才同步,称为关联型同步(逻辑“与”关系)。概述第六十三页,共一百页,编辑于2023年,星期二2023/6/864“或”同步和“与”同步概述第六十四页,共一百页,编辑于2023年,星期二2023/6/865用多个事件的组合发信号给多个任务概述第六十五页,共一百页,编辑于2023年,星期二2023/6/866术语:发送事件集。指在一次发送过程中发往接收者(比如任务)的一个或多个事件的组合。待处理事件集。指已被发送到一个接收者但还没有被接收(即正在等待处理)的所有事件的集合。事件条件。指事件接收者在一次接收过程中期待接收的一个或多个事件的集合。“或”同步:待处理事件集只要包括事件条件中的任一事件即可满足要求;“与”同步:其二是待处理事件集必须包括事件条件中的全部事件方可满足要求。概述第六十六页,共一百页,编辑于2023年,星期二2023/6/867事件机制的主要数据结构事件集控制块:管理所有创建的事件集或者事件集附属于任务,不需创建,其相关参数成为任务控制块的一部分第六十七页,共一百页,编辑于2023年,星期二2023/6/868事件的内部实现机制实例说明-µ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;第六十八页,共一百页,编辑于2023年,星期二2023/6/869事件标志组、事件标志节点及任务控制块之间的关系第六十九页,共一百页,编辑于2023年,星期二2023/6/870事件的主要功能创建事件集删除事件集发送事件(集)接收事件(集)获取有关事件集的各种信息第七十页,共一百页,编辑于2023年,星期二2023/6/871创建事件集申请空闲事件集控制块,设置事件集属性,初始化控制块中的域,分配ID号第七十一页,共一百页,编辑于2023年,星期二2023/6/872创建一个事件标志组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); }第七十二页,共一百页,编辑于2023年,星期二2023/6/873接收事件(集)在接收事件(集)时可以有如下选项,每一类只能选择其一:接收事件(集)时可等待(WAIT)接收者永远等待,直到事件条件被满足后成功返回;接收者根据指定的时限等待。接收事件(集)时不等待(NO_WAIT)待处理事件集必须包含事件条件中的全部事件方可满足要求(EVENT_ALL),即按照“与”条件接收事件待处理事件集只要包含事件条件中的任一事件即可满足要求(EVENT_ANY),即按照“或”条件接收事件第七十三页,共一百页,编辑于2023年,星期二2023/6/874接收(等待)事件标志组的事件标志位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;第七十四页,共一百页,编辑于2023年,星期二2023/6/875接收(等待)事件标志组的事件标志位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); }第七十五页,共一百页,编辑于2023年,星期二2023/6/876

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);}接收(等待)事件标志组的事件标志位OSFlagPend()第七十六页,共一百页,编辑于2023年,星期二2023/6/877添加一个任务到事件标志组等待任务链表中OS_FlagBlock()第七十七页,共一百页,编辑于2023年,星期二2023/6/878接收(无等待地获取)事件标志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;第七十八页,共一百页,编辑于2023年,星期二2023/6/879接收(无等待地获取)事件标志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);}第七十九页,共一百页,编辑于2023年,星期二2023/6/880发送事件(集)调用者(任务或中断)构造一个事件(集),将其发往接收者(比如目标任务)。可能会出现以下几种情况之一:目标任务正在等待的事件条件得到满足,任务就绪;目标任务正在等待的事件条件没有得到满足,该事件(集)被按“或”操作,保存到目标任务的待处理事件集中,目标任务继续等待;目标任务未等待事件(集),该事件(集)被按“或”操作,保存到目标任务的待处理事件集中。第八十页,共一百页,编辑于2023年,星期二2023/6/881发送(置位)事件标志组中的事件标志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;第八十一页,共一百页,编辑于2023年,星期二2023/6/882

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; } pnode=(OS_FLAG_NODE*)pnode->OSFlagNodeNext;//下一个等待事件标志的节点

} if(sched==TRUE)OS_Sched();//如果设置了调度标志,则实施调度 *err=OS_NO_ERR;return(pgrp->OSFlagFlags);}发送(置位)事件标志组中的事件标志OSFlagPost()第八十二页,共一百页,编辑于2023年,星期二2023/6/883删除事件集回收事件集控制块到空闲链中,等待接收该事件集的任务被恢复就绪第八十三页,共一百页,编辑于2023年,星期二2023/6/884删除事件标志组OSFlagDel()OS_FLAG_GRP*OSFlagDel(OS_FLAG_GRP*pgrp,INT8Uopt,INT8U*err){BOOLEANtasks_waiting;OS_FLAG_NODE*pnode; if(pgrp->OSFlagWaitList!=(void*)0)tasks_waiting=TRUE;//有任务等待

elsetasks_waiting=FALSE;//无任务等待

switch(opt){caseOS_DEL_NO_PEND://在无任务等待时才删除事件标志组

if(tasks_waiting==FALSE){//无任务等待,释放控制块到空闲链中

pgrp->OSFlagType=OS_EVENT_TYPE_UNUSED;pgrp->OSFlagWaitList=(void*)OSFlagFreeList; OSFlagFreeList=pgrp; *err=OS_NO_ERR; return((OS_FLAG_GRP*)0); }else{//有任务等待,删除失败 *err=OS_ERR_TASK_WAITING;return(pgrp);}第八十四页,共一百页,编辑于2023年,星期二2023/6/885删除事件标志组OSFlagDel()

caseOS_DEL_ALWAYS://无论是否有任务等待,都删除事件标志组

pnode=(OS_FLAG_NODE*)pgrp->OSFlagWaitList;//获取等待头节点

while(pnode!=(OS_FLAG_NODE*)0){//遍历整个等待任务链,使每个等待任务就绪

OS_FlagTaskRdy(pnode,(OS_FLAGS)0);pnode=(OS_FLAG_NODE*)pnode->OSFlagNodeNext;} pgrp->OSFlagType=OS_EVENT_TYPE_UNUSED;pgrp->OSFlagWaitList=(void*)OSFlagFreeList; OSFlagFreeList=pgrp;//释放控制块回空闲链

if(tasks_waiting==TRUE)OS_Sched();//如果之前有任务等待,*err=OS_NO_ERR; 内核实施调度

return((OS_FLAG_GRP*)0);default: *err=OS_ERR_INVALID_OPT;return(pgrp);}}第八十五页,共一百页,编辑于2023年,星期二2023/6/886事件与其它同步通信机制的综合应用解决复杂的应用设计问题Task1ISR来自某设备的中断Task2消息队列事件标志集信号量01000100①①②②③④④①发送方通过适当的机制向接收方发送信息②发送方设置相应的事件标志③接收方收到事件标志④接收方根据事件标志的指示定向接收信息,达到和不同发送方同步或通信的目的第八十六页,共一百页,编辑于2023年,星期二2023/6/8874.异步信号概述异步信号机制与中断机制的比较异步信号机制与事件机制的比较异步信号机制的主要数据结构异步信号的主要功能

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论