更多信息请访问:Harmonyos技术社区https://harmonyos.51cto.comofficial与华为官方共建概述先看官方对事件的描述。事件是任务间通信的一种机制,可用于任务间的同步。在多任务环境下,任务之间往往需要同步操作,一个等待就是一次同步。事件可以提供一对多和多对多的同步操作。●一对多同步模型:一个任务等待多个事件的触发。可以是任意事件发生时唤醒任务处理事件,也可以是几个事件发生后唤醒任务处理事件。●多对多同步模型:多个任务等待多个事件的触发。鸿蒙提供的事件具有以下特点:●任务通过创建事件控制块来触发事件或等待事件。●事件相互独立,内部实现为一个32位无符号整数,每一位标识一个事件类型。位25不可用,因此最多支持31种事件类型。●事件仅用于任务间的同步,不提供数据传输功能。●多次向事件控制块写入相同的事件类型相当于只写入一次就被清除。●多个任务可以读写同一个事件。●支持事件读写超时机制。再看事件图,注意图中提到了三个概念事件控制块事件任务。接下来结合代码了解事件模块的实现。事件控制块是什么样的?typedefstructtagEvent{UINT32uwEventID;事件类型位,事件ID,每个位标识一个事件类型,表示已经逻辑处理过的事件。*/LOS_DL_LISTstEventList;/**事件<>task三者的关系一定要搞清楚,否则你会看不懂事件模块是怎么工作的。任务是事件的生产者。通过LOS_EventWrite向外部广播XX事件,唤醒之前已经在事件控件中的事件。块中注册的XX任务正在等待XX事件发生。●事件控制块EVENT_CB_S是记录器,它只做两个事件:1.uwEventID记录了哪些事件发生了一点一滴,它只记录,不关心它是如何被消费的。2、stEventList记录了哪些任务在等待事件,但不记录任务在等待哪些事件。任务也是消费者,通过LOS_EventRead进行消费。只有任务本身知道它们想要以何种方式和何种事件消费。首先回忆一下任务结构体LosTaskCB中事件部分的描述如下:typedefstruct{//...去掉无关部分VOID*taskEvent;//任务相关的事件控制块UINT32eventMask;//屏蔽哪些事件UINT32事件模式;//三种事件模式(LOS_WAITMODE_AND,LOS_WAITMODE_OR,LOS_WAITMODE_CLR)}LosTaskCB;taskEvent指向事件控制块EVENT_CB_SeventMask中哪些事件屏蔽了eventMode以及如何消费事件,三种读取模式#defineLOS_WAITMODE_AND4U#defineLOS_WAITMODE_OR2U#defineLOS_WAITMODE_CLR1U?所有事件(LOS_WAITMODE_AND):逻辑与,根据接口传入的事件类型掩码eventMask,只有这些事件发生了才能读取成功,否则任务会阻塞等待或返回错误码?Anyevent(LOS_WAITMODE_OR):逻辑或,根据接口传入的事件类型掩码eventMask,只要有这几个事件发生,任务就可以读取成功,否则任务会阻塞等待或者返回错误码。?清除事件(LOS_WAITMODE_CLR):这是一个额外的读取模式,需要与所有事件模式或任一事件模式(LOS_WAITMODE_AND|LOS_WAITMODE_CLR或LOS_WAITMODE_OR|LOS_WAITMODE_CLR)结合使用。在此模式下,当所有设置的事件模式或任一事件模式读取成功后,事件控制块中对应的事件类型位会自动清零。●一个事件控制块EVENT_CB_S中的事件可以来自多个任务,多个任务也可以同时消费事件控制块中的事件,这些任务之间没有关系!函数列表事件可以应用于多任务同步场景,在某些同步场景下可以替代信号量。如果你了解OsEventWrite和OsEventRead,你就会了解事件模块。事件初始化->LOS_EventInit//初始化一个事件控制块LITE_OS_SEC_TEXT_INITUINT32LOS_EventInit(PEVENT_CB_SeventCB){UINT32intSave;intSave=LOS_IntLock();//锁定中断eventCB->uwE/ventID=0;每一位代表一个事件类型(0表示该事件类型没有发生,1表示该事件类型已经发生)LOS_ListInit(&eventCB->stEventList);//初始化事件列表LOS_IntRestore(intSave);//恢复中断returnLOS_OK;}代码解释:●事件是共享资源,运行过程中不会发生中断。●初始化两个记录器uwEventIDstEventList事件产生过程->OsEventWriteLITE_OS_SEC_TEXTVOIDOsEventWriteUnsafe(PEVENT_CB_SeventCB,UINT32events,BOOLonce,UINT8*exitFlag){LosBaskCB*ULCUsresumedTask=NS*nextTask=NULL;BOOLschedFlag=FALSE/wevent-labels=;eventCB;对应位if(!LOS_ListEmpty(&eventCB->stEventList)){//等待事件列表判断处理等待事件的任务for(resumedTask=LOS_DL_LIST_ENTRY((&eventCB->stEventList)->pstNext,LosTaskCB,pendList);&resumedTask->pendList!=&eventCB->stEventList;){//循环获取任务列表nextTask=LOS_DL_LIST_ENTRY(resumedTask->pendList.pstNext,LosTaskCB,pendList);//获取任务实体if(OsEventResume(resumedTask,eventCB,events)){//是否恢复任务schedFlag=TRUE;//任务已加入就绪队列,申请已调度一次}if(once==TRUE){//任务是否只处理一次break;//退出循环}resumedTask=nextTask;//检查链表中的下一个任务}}if((exitFlag!=NULL)&&(schedFlag==TRUE)){//是否让外部调度*exitFlag=1;}}//写事件LITE_OS_SEC_TEXTSTATICUINT32OsEventWrite(PEVENT_CB_SeventCB,UINT32events,BOOLonce){UINT32intSave;UINT8exitFlag=0;SCHEDULER_LOCK(intSave);//禁用调度OsEventWriteUnsafe(events,CB,event,&ULOnce,&intSaveFlag);//允许调度if(exitFlag==1){//调度需要发生LOS_MpSchedule(OS_MP_CPU_ALL);//通知所有CPU调度LOS_Schedule();//执行调度}returnLOS_OK;}代码解释:1.粘贴相应的位事件标签,eventCB->uwEventID|=events;请注意,uwEventID由位管理。每一位代表是否有事件被写入,例如uwEventID=00010010表示已经产生了1、4个事件2.从stEventList链表中循环出来,等待这个事件任务判断是否唤醒任务。OsEventResume//事件恢复,判断是否唤醒任务->eventMask&events)!=0))||((resumedTask->eventMode&LOS_WAITMODE_AND)&&((resumedTask->eventMask&eventCB->uwEventID)==resumedTask->eventMask))){//逻辑与和逻辑或处理exitFlag=1;resumedTask->taskEvent=NULL;OsTaskWake(resumedTask);//唤醒任务并加入就绪队列}returnexitFlag;}3.唤醒任务OsTaskWake只是将任务重新加入就绪队列,需要马上申请一个调度LOS_Schedule。事件消耗过程->oseventReadlite_Sec_textStaticuInt32oseVentRead(pevent_cb_seventcb,uint32eventmask,uint32mode,uint32TimeOut,uint32Time,boolonce,boolonce)(intSave);returnret;}//读取指定事件类型的实现函数,超时时间为相对时间:单位为TickLITE_OS_SEC_TEXTSTATICUINT32OsEventReadImp(PEVENT_CB_SeventCB,UINT32eventMask,UINT32mode,UINT32timeout,BOOLonce){UINT32ret=0;LosTaskCB*runTask=OsCurrTaskGet();runentTask->event=eventMask;runTask->eventMode=mode;runTask->taskEvent=eventCB;//事件控制块ret=OsTaskWait(&eventCB->stEventList,timeout,TRUE);//任务进入等待状态,挂入阻塞列表if(ret==LOS_ERRNO_TSK_TIMEOUT){//如果返回超时uwEventID,eventMask,mode);//检查事件是否符合预期returnret;}代码解释:●事件控制块由任务使用,任务提供读取事件的条件。1、eventMask告诉系统屏蔽这些事件,对被屏蔽的事件不感兴趣。2、eventMode使用什么样的方式来消费事件?是必须满足所有给定条件,还是必须满足其中一个条件才能响应。3.条件给定后,自己进入等待状态OsTaskWait,等待超时决定多久,任务说了算。4、OsEventPoll检测事件是否符合预期,什么意思?看看它的代码就知道了//根据用户传入的事件值和事件Mask以及验证方式,返回用户传入的事件是否符合预期LITE_OS_SEC_TEXTUINT32OsEventPoll(UINT32*eventID,UINT32eventMask,UINT32mode){UINT32ret=0;//事件是否发生LOS_ASSERT(OsIntLocked());//断言不允许中断LOS_ASSERT(LOS_SpinHeld(&g_taskSpin));//任务自旋锁if(mode&LOS_WAITMODE_OR){//如果模式是读掩码中的任何事件if((*eventID&eventMask)!=0){ret=*eventID&eventMask;//Happened}}else{//等待所有事件发生if((eventMask!=0)&&(eventMask==(*eventID&eventMask))){//所有事件必须满足ret=*eventID&eventMask;//发生}}if(ret&&(mode&LOS_WAITMODE_CLR)){//是否清除事件*eventID=*eventID&~ret;}returnret;}编程实例本例实现如下流程实例,任务Example_TaskEntry创建任务Example_Event,Example_Event读取事件块,Example_TaskEntry向任务写入事件。您可以通过示例日志中打印的顺序了解事件操作伴随的任务切换。●在任务Example_TaskEntry中创建任务Example_Event,任务Example_Event的优先级高于Example_TaskEntry。●读取任务Example_Event中的事件0x00000001,阻塞,发生任务切换,执行任务Example_TaskEntry。●将任务Example_TaskEntry中的事件0x00000001写入任务Example_Event,发生任务切换,执行任务Example_Event。●Example_Event一直执行到任务结束。●Example_TaskEntry一直执行到任务结束。#include"los_event.h"#include"los_task.h"#include"securec.h"/*任务ID*/UINT32g_testTaskId;/*事件控制结构*/EVENT_CB_Sg_exampleEvent;/*等待事件类型*/#defineEVENT_WAIT0x00000001/*使用casetaskentryfunction*/VOIDExample_Event(VOID){UINT32ret;UINT32event;/*超时等待模式读取事件,超时时间为100ticks,如果100ticks后没有读取指定事件,则读取事件超时,任务唤醒直接up*/printf("Example_Eventwaitevent0x%x\n",EVENT_WAIT);event=LOS_EventRead(&g_exampleEvent,EVENT_WAIT,LOS_WAITMODE_AND,100);if(event==EVENT_WAIT){printf("Example_Event,readevent:0x%x\n",event);}else{printf("Example_Event,readeventtimeout\n");}}UINT32Example_TaskEntry(VOID){UINT32ret;TSK_INIT_PARAM_Stask1;/*事件初始化*/ret=LOS_EventInit(&g_exampleEvent);if(ret!=LOS_OK){printf("initeventfailed.\n");return-1;}/*创建任务*/(VOID)memset_s(&task1,sizeof(TSK_INIT_PARAM_S),0,sizeof(TSK_INIT_PARAM_S));task1.pfnTaskEntry=(TSK_ENTRY_FUNC)Example_Event;task1.pcName="EventTsk1";task1.uwStackSize=OS_TSK_DEFAULT_STACK_SIZE;task1.usTaskPrio=5;ret=LOS_TaskCreate(&g_testTaskId,&task1);if(ret!=LOS_OK){printf("taskcreatefailed.\n");returnLOS_NOK;}/*写入g_testTaskId等待事件*/printf("Example_TaskEntrywriteevent.\n");ret=LOS_EventWrite(&g_exampleEvent,EVENT_WAIT);if(ret!=LOS_OK){printf("eventwritefailed.\n");returnLOS_NOK;}/*清除标志*/printf("EventMask:%d\n",g_exampleEvent.uwEventID);LOS_EventClear(&g_exampleEvent,~g_exampleEvent.uwEventID);printf("EventMask:%d\n",g_exampleEvent.uwEventID);/*删除任务*/ret=LOS_TaskDelete(g_testTaskId);if(ret!=LOS_OK){printf("taskdeletefailed.\n");returnLOS_NOK;}returnLOS_OK;}Example_Eventwaitevent0x1Example_TaskEntrywriteevent.Example_Event,readevent:0x1EventMask:1EventMask:0参与贡献●访问注解仓库地址Fork本仓库>>x新建Feat_分支>>提交代码评论>>新建一个PullRequest●新建一个Issue更多信息请访问:与华为官方共建的鸿蒙技术社区https://harmonyos.51cto.com