嵌入式系统开发 -基于分布式系统OpenHarmony 课件 P03-OpenHarmony内核进阶分析_第1页
嵌入式系统开发 -基于分布式系统OpenHarmony 课件 P03-OpenHarmony内核进阶分析_第2页
嵌入式系统开发 -基于分布式系统OpenHarmony 课件 P03-OpenHarmony内核进阶分析_第3页
嵌入式系统开发 -基于分布式系统OpenHarmony 课件 P03-OpenHarmony内核进阶分析_第4页
嵌入式系统开发 -基于分布式系统OpenHarmony 课件 P03-OpenHarmony内核进阶分析_第5页
已阅读5页,还剩93页未读 继续免费阅读

下载本文档

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

文档简介

基于OpenHarmony的嵌入式开发

第三章OpenHarmony内核进阶分析安全边距3.1进程间通信[3.1.0]进程间通信简介

LiteOS-M调度对象是任务Task,LiteOS-A是进程Process和任务进程间通信(Inter-ProcessCommunication,IPC)指操作系统提供的,供进程(任务)之间共享数据的机制和方法,应用程序可以通过IPC实现相互之间的通信,IPC关系着操作系统内核的效率问题。

LiteOS-M所支持的IPC类型包括:事件(Event)、互斥锁(Mutex)、队列(Queue)和信号量(Semaphore)。

LiteOS-A除了支持上述类型之外,还支持信号(Signal)和用户态快速互斥锁(Futex)等。

IPC具有很强的通用性,本小节不区分LiteOS-M和LiteOS-A。基于OpenHarmony的嵌入式开发2安全边距3.1进程间通信[3.1.1]事件Event事件:用于任务间的同步操作接口:事件初始化、事件读写、事件清零、事件销毁等表示:用32位无符号整型变量来表示的,其中每一位表示一种事件类型,LiteOS共表达了31种可用的事件类型(第25位不可用)。基于OpenHarmony的嵌入式开发3/***@ingrouplos_event*Eventcontrolstructure*/typedefstructtagEvent{UINT32uwEventID;

/**<Eventmaskintheeventcontrolblock,

indicatingtheeventthathasbeenlogicallyprocessed.*/LOS_DL_LISTstEventList;

/**<Eventcontrolblocklinkedlist*/}EVENT_CB_S,*PEVENT_CB_S;事件控制块安全边距3.1进程间通信[3.1.1]事件(Event)LitsOS事件的特点:(1)任务间的事件同步,可以是一对多,也可以多对多的。一对多表示一个任务可以等待多个事件,多对多则表示多个任务可以等待多个事件。但是一次写事件最多触发一个任务从阻塞中醒来。(2)事件具有读超时机制。(3)事件只做任务间同步,不传输具体数据。(4)多次向事件控制块写入同一事件类型,在被清零前等效于只写入一次。(5)多个任务可以对同一事件进行读写操作。(6)支持事件读写超时机制。基于OpenHarmony的嵌入式开发4安全边距3.1进程间通信[3.1.1]事件(Event)LitsOS事件的运作流程示例基于OpenHarmony的嵌入式开发5创建一个事件控制块,通过该控制块维护一个已处理的事件集合,以及等待特定事件的任务链表。向事件控制块中写入指定的事件。事件控制块更新事件集合,并遍历任务链表,根据任务等待具体条件满足情况决定是否唤醒相关任务。如果读取的事件已存在则会直接同步返回。其他情况会根据超时时间或事件触发情况来决定返回时机。如果等待的事件条件在超时时间耗尽之前到达,则阻塞任务会被直接唤醒,否则只能在超时时间耗尽时,该任务才会被唤醒。读事件条件满足与否取决于参数eventMask(掩码)和mode(模式)。LOS_EventInit

LOS_EventWrite

LOS_EventRead

LOS_EventPool

安全边距3.1进程间通信[3.1.1]事件(Event)LitsOS事件的运作流程示例基于OpenHarmony的嵌入式开发6完成程序既定的功能后,还需要根据指定掩码,对事件控制块的事件集合进行清零操作。当掩码为0时,表示将事件集合全部清零。当掩码为0xffff时,表示不清除任何事件,保持事件集合原状。向事件控制块中写入指定的事件。事件控制块更新事件集合,并遍历任务链表,根据任务等待具体条件满足情况决定是否唤醒相关任务。销毁指定的事件控制块LOS_EventClear

LOS_EventDestroy

LOS_EventInit

LOS_EventWrite

LOS_EventRead

LOS_EventPool

安全边距3.1进程间通信[3.1.1]事件(Event)LitsOS事件的运作流程示例:一种开发流程参考(1)初始化事件控制块;(2)阻塞读事件控制块;(3)写入相关事件;(4)阻塞任务被唤醒,读取事件并检查是否满足要求;(5)处理事件控制块;(6)事件控制块销毁。基于OpenHarmony的嵌入式开发7初始化后的任意时间、任意程序完成STATICINLINEVOIDOsWatchCmdUsage(VOID)

{PRINTK("\nUsage:watch\n");PRINTK("watch[options]command\n");}watch命令:周期性监测某个命令的运行状态安全边距3.1进程间通信[3.1.1]事件(Event)LitsOS事件的运作流程示例:watch命令执行机制课堂思考问题:watch命令是如何执行的基于OpenHarmony的嵌入式开发8/kernel/liteos_a/shell/full/src/cmds/watch_sehllcmd.cSHELLCMD_ENTRY()OsShellCmdWatch()

OsWatchCmdUsage()OsWatchOverFunc()OsWatchTaskCreate()if((argc==1)&&(strcmp(argv[0],"--over")==0)){ret=OsWatchOverFunc();

returnret;}if(argc==0){OsWatchCmdUsage();returnOS_ERROR;}if(argv==NULL){OsWatchCmdUsage();returnOS_ERROR;}argc:argumentcount,传入的参数个数argc==0:传入参数数量为0(调用命令不合法)argv:argumentvector,传入的参数列表argv==NULL:没有传入参数(调用命令不合法)STATICINLINEVOIDOsWatchCmdUsage(VOID)

{PRINTK("\nUsage:watch\n");PRINTK("watch[options]command\n");}watchItem=(WatchCB*)malloc(sizeof(WatchCB));(VOID)memset_s(watchItem,sizeof(WatchCB),0,sizeof(WatchCB));……;err=OsWatchOptionParsed(argc,&argoff,argv,watchItem);……;err=OsWatchCmdSplice(argc,argoff,argv,watchItem);……;ret=OsWatchTaskCreate(watchItem);LOS_EventWrite(&g_watchCmd->watchEvent,0x01);安全边距3.1进程间通信[3.1.1]事件(Event)LitsOS事件的运作流程示例:watch命令执行机制课堂思考问题:watch命令是如何执行的基于OpenHarmony的嵌入式开发9SHELLCMD_ENTRY()OsShellCmdWatch()

OsWatchCmdUsage()OsWatchOverFunc()OsWatchTaskCreate()ret=OsWatchTaskCreate(watchItem);UINT32OsWatchTaskCreate(WatchCB*watchItem){

UINT32watchTaskId=0;

……;

ret=LOS_EventInit(&watchItem->watchEvent);

if(ret!=0){

……

}

initParam.pfnTaskEntry=(TSK_ENTRY_FUNC)OsShellCmdDoWatch;initParam.usTaskPrio=10;

/*10:shellcmd_watchtaskpriority*/initParam.auwArgs[0]=(UINTPTR)watchItem;initParam.uwStackSize=0x3000;

/*0x3000:stacksizeofshellcmd_watchtask*/initParam.pcName="shellcmd_watch";initParam.uwResved=LOS_TASK_STATUS_DETACHED;

ret=LOS_TaskCreate(&watchTaskId,&initParam);if(ret!=0){

……

}returnret;}核心功能安全边距3.1进程间通信[3.1.1]事件(Event)LitsOS事件的运作流程示例:watch命令执行机制-核心功能基于OpenHarmony的嵌入式开发10STATICVOIDOsShellCmdDoWatch(UINTPTRarg1)

{

WatchCB*watchItem=(WatchCB*)arg1;

……while(watchItem->count--){printf("\033[2J\n");if(watchItem->title){

PrintTime();}(VOID)ShellMsgParse(watchItem->cmdbuf);ret=LOS_EventRead(&watchItem->watchEvent,0x01,LOS_WAITMODE_OR|LOS_WAITMODE_CLR,

watchItem->interval);if(ret==0x01){break;}}(VOID)LOS_EventDestroy(&watchItem->watchEvent);

……}STATICVOIDPrintTime(VOID)

{structtimeval64stNowTime={0};if(gettimeofday64(&stNowTime,NULL)==0){PRINTK("%s",ctime64(&(stNowTime.tv_sec)));}}typedefstruct{BOOLtitle;/*whethertohidethetimestamps*/UINT32count;/*thetotalnumberofcommandexecutions*/UINT32interval;/*runningcycleofthecommand*/

EVENT_CB_SwatchEvent;/*eventhandleofthewatchstructure*/

CHARcmdbuf[CMD_MAX_LEN];/*thecommandtowatch*/}WatchCB;安全边距3.1进程间通信[3.1.1]事件(Event)LitsOS事件的运作流程示例:watch命令执行机制-核心功能基于OpenHarmony的嵌入式开发11STATICVOIDOsShellCmdDoWatch(UINTPTRarg1)

{WatchCB*watchItem=(WatchCB*)arg1;

……while(watchItem->count--){printf("\033[2J\n");if(watchItem->title){PrintTime();}

(VOID)ShellMsgParse(watchItem->cmdbuf);ret=LOS_EventRead(&watchItem->watchEvent,0x01,LOS_WAITMODE_OR|LOS_WAITMODE_CLR,

watchItem->interval);if(ret==0x01){break;}}(VOID)LOS_EventDestroy(&watchItem->watchEvent);

……}externUINT32LOS_EventRead(PEVENT_CB_SeventCB,UINT32eventMask,UINT32mode,UINT32timeOut);eventCB:PointertotheeventcontrolblocktobecheckedeventMask:Maskoftheeventexpectedtooccurbytheuser,indicatingtheeventobtainedaftermode

:Eventreadingmode.timeOut:Timeoutintervalofeventreading(unit:Tick).retval0:Theeventexpectedbytheuserdoesnotoccur.retval#UINT32:Theeventexpectedbytheuseroccurs.返回值为0时,表示设定的事件并未发生,返回其他32位数值时表示发生了该事件。LOS_EventWrite(&g_watchCmd->watchEvent,0x01);列印出命令的执行信息循环检测事件安全边距3.1进程间通信[3.1.1]事件(Event)LitsOS事件的运作流程示例:watch

task基于OpenHarmony的嵌入式开发12PrintTime();ShellMsgParse(watchItem->cmdbuf);1事件有没有传递信息?有2事件传递了什么信息?状态(单一数值信息,例如0x01)安全边距3.1进程间通信[3.1.2]互斥锁(Mutex)

互斥锁(互斥量):一种特殊的二值性信号量,使用或未被使用状态

实现独占式访问:实现对共享资源的独占式处理,在有多个线程执行的环境中强制限制对资源的访问,实现对共享资源的保护基于OpenHarmony的嵌入式开发13/***@ingrouplos_mux*Mutexobject.*/typedefstruct{UINT8muxStat;/**<StateOS_MUX_UNUSED,OS_MUX_USED*/UINT16muxCount;/**<Timesoflockingamutex*/UINT32muxID;/**<HandleID*/LOS_DL_LISTmuxList;/**<Mutexlinkedlist*/LosTaskCB*owner;/**<Thecurrentthreadthatislockingamutex*/UINT16priority;/**<Priorityofthethreadthatislockingamutex*/}LosMuxCB;LiteOS-M互斥锁控制块安全边距3.1进程间通信[3.1.2]互斥锁(Mutex)

互斥锁:使用时上锁(申请)、未被使用状态时释放基于OpenHarmony的嵌入式开发14线程1访问某个公共资源,互斥锁上锁,线程2不能访问被挂起。线程1释放该公共资源,互斥锁释放,线程2才能够访问该公共资源。安全边距3.1进程间通信[3.1.2]互斥锁(Mutex)

互斥锁:LiteOS-M和LiteOS-A的互斥锁接口基于OpenHarmony的嵌入式开发15LiteOS-M接口接口功能说明LOS_MuxCreate创建互斥锁LOS_MuxDelete删除指定的互斥锁LOS_MuxPend申请指定的互斥锁LOS_MuxPost释放指定的互斥锁LiteOS-A接口名称接口功能说明LOS_MuxInit互斥锁初始化LOS_MuxDestroy销毁指定的互斥锁LOS_MuxLock申请指定的互斥锁LOS_MuxTrylock尝试申请指定的互斥锁,不阻塞LOS_MuxUnlock释放指定的互斥锁LOS_MuxIsValid判断互斥锁释放有效LOS_MuxAttrInit互斥锁属性初始化LOS_MuxAttrDestroy销毁指定的互斥锁属性…………LiteOS-A的互斥锁更加复杂复杂在属性上typedefstruct{UINT8protocol;UINT8prioceiling;UINT8type;UINT8reserved;}LosMuxAttr;安全边距3.1进程间通信[3.1.2]互斥锁(Mutex)

互斥锁:LiteOS-A的复杂属性基于OpenHarmony的嵌入式开发16typedefstruct{UINT8protocol;UINT8prioceiling;UINT8type;UINT8reserved;}LosMuxAttr;协议属性:处理不同优先级的任务申请互斥锁(1)LOS_MUX_PRIO_NONE,该属性不对申请互斥锁的任务的优先级进行继承或保护操作。(2)LOS_MUX_PRIO_INHERIT,该属性为优先级的继承属性,是互斥锁的默认属性,对申请互斥锁的任务的优先级进行继承。在互斥锁设置为本协议属性情况下,申请互斥锁时,如果高优先级任务阻塞于互斥锁,则把持有互斥锁任务的优先级备份到任务控制块的优先级位图中,然后把任务优先级设置为和高优先级任务相同的优先级;持有互斥锁的任务释放互斥锁时,从任务控制块的优先级位图恢复任务优先级。(3)LOS_MUX_PRIO_PROTECT,该属性为优先级的保护属性,对申请互斥锁的任务的优先级进行保护。在互斥锁设置为本协议属性情况下,申请互斥锁时,如果任务优先级小于互斥锁优先级上限,则把任务优先级备份到任务控制块的优先级位图中,然后把任务优先级设置为互斥锁优先级上限属性值;释放互斥锁时,从任务控制块的优先级位图恢复任务优先级。安全边距3.1进程间通信[3.1.2]互斥锁(Mutex)

互斥锁:LiteOS-A的复杂属性基于OpenHarmony的嵌入式开发17typedefstruct{UINT8protocol;UINT8prioceiling;UINT8type;UINT8reserved;}LosMuxAttr;类型属性:用于标记是否检测死锁和是否支持递归持有(1)LOS_MUX_NORMAL,普通互斥锁,不会检测死锁问题。如果任务试图对一个互斥锁重复持有,将会引起这个线程的死锁。如果试图释放一个由别的任务持有的互斥锁,或者如果一个任务试图重复释放互斥锁都会引发不可预料的结果。(2)LOS_MUX_RECURSIVE,递归互斥锁,是互斥锁的默认属性。允许同一个任务对互斥锁进行多次持有锁,持有锁次数和释放锁次数相同,其他任务才能持有该互斥锁。如果试图持有已经被其他任务持有的互斥锁,或者如果试图释放已经被释放的互斥锁,会返回错误码。(3)LOS_MUX_ERRORCHECK,错误检测互斥锁,会自动检测死锁。在互斥锁设置为本类型属性情况下,如果任务试图对一个互斥锁重复持有,或者试图释放一个由别的任务持有的互斥锁,或者如果一个任务试图释放已经被释放的互斥锁,都会返回错误码。安全边距3.1进程间通信[3.1.2]互斥锁(Mutex)

互斥锁:LiteOS-M和LiteOS-A的互斥锁接口基于OpenHarmony的嵌入式开发18LiteOS-M接口接口功能说明LOS_MuxPend申请指定的互斥锁LOS_MuxPost释放指定的互斥锁LiteOS-A接口名称接口功能说明LOS_MuxLock申请指定的互斥锁LOS_MuxUnlock释放指定的互斥锁互斥锁的申请有三种模式:(1)无阻塞模式:任务需要申请互斥锁,若该互斥锁当前没有任务持有,或者持有该互斥锁的任务和申请该互斥锁的任务为同一个任务,则申请成功;(2)永久阻塞模式:任务需要申请互斥锁,若该互斥锁当前没有被占用,则申请成功。否则,该任务进入阻塞态,系统切换到就绪任务中优先级高者继续执行。任务进入阻塞态后,直到有其他任务释放该互斥锁,阻塞任务才会重新得以执行;(3)定时阻塞模式:任务需要申请互斥锁,若该互斥锁当前没有被占用,则申请成功。否则该任务进入阻塞态,系统切换到就绪任务中优先级高者继续执行。任务进入阻塞态后,指定时间超时前有其他任务释放该互斥锁,或者用户指定时间超时后,阻塞任务才会重新得以执行。互斥锁的释放有两种情况:(1)如果有任务阻塞于指定互斥锁,则唤醒被阻塞任务中优先级高的,该任务进入就绪态,并进行任务调度;(2)如果没有任务阻塞于指定互斥锁,则互斥锁释放成功。安全边距3.1进程间通信[3.1.2]互斥锁(Mutex)

互斥锁:互斥锁的应用示例(1)任务Example_TaskEntry创建一个互斥锁,用于锁任务调度。分别创建了两个任务Example_MutexTask1和Example_MutexTask2。其中,Example_MutexTask2的优先级高于Example_MutexTask1,然后解锁任务调度。(2)Example_MutexTask2首先被调度,并以永久阻塞模式申请互斥锁。该任务成功获取到该互斥锁后,启动任务休眠,休眠时间为100Tick,Example_MutexTask2挂起,Example_MutexTask1被唤醒。(3)Example_MutexTask1以定时阻塞模式申请互斥锁,等待时间为10Tick。但是,因互斥锁被Example_MutexTask2所持有,Example_MutexTask1会被挂起。当10Tick超时时间到达后,Example_MutexTask1被唤醒,再以永久阻塞模式申请互斥锁,但因互斥锁仍然被Example_MutexTask2持有,Example_MutexTask1再次被挂起。(4)100Tick的休眠时间到达后,Example_MutexTask2被唤醒,释放互斥锁,然后唤醒Example_MutexTask1。Example_MutexTask1成功获取到互斥锁后,释放,删除互斥锁。基于OpenHarmony的嵌入式开发19安全边距3.1进程间通信[3.1.2]互斥锁(Mutex)

互斥锁:互斥锁的应用示例-

Example_MutexTask1基于OpenHarmony的嵌入式开发20VOIDExample_MutexTask1(VOID){UINT32ret;printf("task1trytogetmutex,wait10ticks.\n");

ret=LOS_MuxLock(&g_testMux,10);

//申请互斥锁

if(ret==LOS_OK){printf("task1getmutexg_testMux.\n");

LOS_MuxUnlock(&g_testMux);

//释放互斥锁

return;

}if(ret==LOS_ETIMEDOUT){printf("task1timeoutandtrytogetmutex,waitforever.\n");

ret=LOS_MuxLock(&g_testMux,LOS_WAIT_FOREVER);

//申请互斥锁

if(ret==LOS_OK){printf("task1waitforever,getmutexg_testMux.\n");

LOS_MuxUnlock(&g_testMux);

//释放互斥锁

LOS_MuxDestroy(&g_testMux);

//删除互斥锁

printf("task1postanddeletemutexg_testMux.\n");return;

}}

return;

}安全边距3.1进程间通信[3.1.2]互斥锁(Mutex)

互斥锁:互斥锁的应用示例-

Example_MutexTask2等基于OpenHarmony的嵌入式开发21VOIDExample_MutexTask2(VOID){printf("task2trytogetmutex,waitforever.\n");

(VOID)LOS_MuxLock(&g_testMux,LOS_WAIT_FOREVER);

//申请互斥锁

printf("task2getmutexg_testMuxandsuspend100ticks.\n");

LOS_TaskDelay(100);

//任务休眠100Ticksprintf("task2resumedandposttheg_testMux\n");

LOS_MuxUnlock(&g_testMux);

//释放互斥锁

return;}UINT32Example_MutexEntry(VOID){UINT32ret;TSK_INIT_PARAM_Stask1;TSK_INIT_PARAM_Stask2;

LOS_MuxInit(&g_testMux,NULL);//初始化互斥锁

LOS_TaskLock();

//锁任务调度

//创建任务1

……

//创建任务2

……安全边距3.1进程间通信[3.1.2]互斥锁(Mutex)

互斥锁:互斥锁的应用示例-

Example_MutexEntry基于OpenHarmony的嵌入式开发22

//创建任务1memset(&task1,0,sizeof(TSK_INIT_PARAM_S));

task1.pfnTaskEntry=(TSK_ENTRY_FUNC)Example_MutexTask1;task1.pcName="MutexTsk1";task1.uwStackSize=LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;

task1.usTaskPrio=5;

//低优先级

ret=LOS_TaskCreate(&g_testTaskId01,&task1);if(ret!=LOS_OK){printf(“task1createfailed.\n”);returnLOS_NOK;

}

//创建任务2memset(&task2,0,sizeof(TSK_INIT_PARAM_S));

task2.pfnTaskEntry=(TSK_ENTRY_FUNC)Example_MutexTask2;task2.pcName="MutexTsk2";task2.uwStackSize=LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;

task2.usTaskPrio=4;

//高优先级

ret=LOS_TaskCreate(&g_testTaskId02,&task2);if(ret!=LOS_OK){printf("task2createfailed.\n");returnLOS_NOK;}

LOS_TaskUnlock();

//解锁任务调度

returnLOS_OK;哪个任务先开始运行?分析一下程序运行结果安全边距3.1进程间通信[3.1.2]互斥锁(Mutex)

互斥锁:互斥锁的应用示例-分析运行结果(均执行成功)基于OpenHarmony的嵌入式开发23Example_MutexEntryret=LOS_TaskCreate(&g_testTaskId01,&task1);

//优先级5ret=LOS_TaskCreate(&g_testTaskId02,&task2);

//优先级4Example_MutexTask1①

printf("task1trytogetmutex,wait10ticks.\n");②

printf("task1getmutexg_testMux.\n");//如果等待超时③

printf("task1timeoutandtrytogetmutex,waitforever.\n");//如果申请到互斥锁④

printf("task1waitforever,getmutexg_testMux.\n");//互斥锁销毁之后⑤

printf("task1postanddeletemutexg_testMux.\n");Example_MutexTask2⑥

printf("task2trytogetmutex,waitforever.\n");⑦

printf(“task2getmutexg_testMuxandsuspend100ticks.\n”);⑧

printf("task2resumedandposttheg_testMux\n");创建任务1和任务2任务1优先级为5任务2优先级为4,优先执行课堂思考/讨论程序运行结果安全边距3.1进程间通信[3.1.2]互斥锁(Mutex)

互斥锁:互斥锁的应用示例-分析运行结果(均执行成功)基于OpenHarmony的嵌入式开发24Example_MutexEntryret=LOS_TaskCreate(&g_testTaskId01,&task1);

//优先级5ret=LOS_TaskCreate(&g_testTaskId02,&task2);

//优先级4Example_MutexTask1printf("task1trytogetmutex,wait10ticks.\n");printf("task1getmutexg_testMux.\n");//如果等待超时printf("task1timeoutandtrytogetmutex,waitforever.\n");//如果申请到互斥锁printf("task1waitforever,getmutexg_testMux.\n");//互斥锁销毁之后printf("task1postanddeletemutexg_testMux.\n");Example_MutexTask2printf("task2trytogetmutex,waitforever.\n");printf(“task2getmutexg_testMuxandsuspend100ticks.\n”);printf("task2resumedandposttheg_testMux\n");程序运行结果如下task2trytogetmutex,waitforever.task2getmutexg_testMuxandsuspend100ticks.task1trytogetmutex,wait10ticks.task1timeoutandtrytogetmutex,waitforever.task2resumedandposttheg_testMuxtask1waitforever,getmutexg_testMux.task1postanddeletemutexg_testMux.创建任务1和任务2任务1优先级为5任务2优先级为4,优先执行安全边距3.1进程间通信[3.1.3]队列(Queue)队列(消息队列):一种常用于任务间通信的数据结构

队列接收来自任务或中断的不固定长度消息,并根据不同的接口确定传递的消息是否存放在队列空间中(事件只能传输状态信息、互斥锁无法传输信息),队列能够在任务之间传输更丰富的信息。

任务能够从队列里面读取消息,当队列中的消息为空时,挂起读取任务;当队列中有新消息时,挂起的读取任务被唤醒并处理新消息。任务也能够向队列中写入消息,当队列已经写满消息时,挂起写入任务;当队列中有空闲消息节点时,挂起的写入任务被唤醒并写入消息。

可以通过调整读队列和写队列的超时时间来调整读写接口的阻塞模式,如果将读队列和写队列的超时时间设置为0,就不会挂起任务,接口会直接返回,这就是非阻塞模式。反之,如果将都队列和写队列的超时时间设置为大于0的时间,就会以阻塞模式运行。基于OpenHarmony的嵌入式开发25安全边距3.1进程间通信[3.1.3]队列(Queue)队列(消息队列):一种常用于任务间通信的数据结构

消息队列提供了异步处理机制,允许将一个消息放入队列,但不立即处理,具有异步通信和缓冲作用。队列具有如下特性。

(1)消息以先进先出的方式排队,支持异步读写。

(2)读队列和写队列都支持超时机制。

(3)每读取一条消息,就会将该消息节点设置为空闲。

(4)发送消息类型由通信双方约定,可以允许不同长度(不超过队列的消息节点大小)的消息。

(5)一个任务能够与任意一个消息队列进行消息的接收和发送消息。

(6)多个任务能够从同一个消息队列接收和发送消息。

(7)创建队列时所需的队列空间,接口内系统自行动态申请内存。基于OpenHarmony的嵌入式开发26任务与消息队列是多对多的关系安全边距3.1进程间通信[3.1.3]队列(Queue)控制块:los_queue.h(LiteOS-M)和los_queue_pri.h(LiteOS-A)基于OpenHarmony的嵌入式开发27typedefstruct{UINT8*queue;

/**<Pointertoaqueuehandle*/UINT16queueState;

/**<Queuestate*/UINT16queueLen;

/**<Queuelength*/UINT16queueSize;

/**<Nodesize*/UINT16queueID;

/**<queueID*/UINT16queueHead;

/**<Nodehead*/UINT16queueTail;

/**<Nodetail*/UINT16readWriteableCnt[OS_READWRITE_LEN];

/**<Countofreadableorwritableresources,0:readable,1:writable*/LOS_DL_LISTreadWriteList[OS_READWRITE_LEN];

/**<Pointertothelinkedlisttobereadorwritten,

0:readlist,

1:writelist*/LOS_DL_LISTmemList;

/**<Pointertothememorylinkedlist*/}LosQueueCB;LiteOS-M队列控制块#defineOS_QUEUE_UNUSED

0#defineOS_QUEUE_INUSED

1#defineOS_READWRITE_LEN

2readWriteableCnt[0]表示队列中可读消息数,readWriteableCnt[1]表示队列中可写消息数readWriteList[0]表示读取链表readWriteList[1]表示写入链表安全边距3.1进程间通信[3.1.3]队列(Queue)队列(消息队列)的若干使用基本要点(1)创建队列时,创建队列成功会返回队列ID。(2)在队列控制块中维护着一个消息头节点位置Head和一个消息尾节点位置Tail,表示当前队列中消息的存储情况。Head表示队列中被占用的消息节点的起始位置,Tail表示被占用的消息节点的结束位置,也是空闲消息节点的起始位置。队列创建时Head和Tail均指向起始位置。基于OpenHarmony的嵌入式开发28安全边距3.1进程间通信[3.1.3]队列(Queue)队列(消息队列)的若干使用基本要点

(3)在写队列时,将根据readWriteableCnt[1]判断队列是否可以写入,不能对已满的队列(readWriteableCnt[1]为0)进行写操作。写队列支持两种写入方式:向队列尾节点写入,也可以向队列头节点写入。尾节点写入时,根据Tail找到起始空闲消息节点作为数据写入对象,如果Tail已经指向队列尾部则采用回卷方式。头节点写入时,将Head的前一个节点作为数据写入对象,如果Head指向队列起始位置则采用回卷方式。(4)在读队列时,将根据readWriteableCnt[0]判断队列是否有消息需要读取,对全部空闲的队列(readWriteableCnt[0]为0)进行读操作会引起任务挂起。如果队列可以读取消息,则根据Head找到最先写入队列的消息节点进行读取。如果Head已经指向队列尾部则采用回卷方式。(5)在删除队列时,根据队列ID找到对应队列,把队列状态置为未使用,把队列控制块置为初始状态,并释放队列所占内存。基于OpenHarmony的嵌入式开发29安全边距3.1进程间通信[3.1.3]队列(Queue)队列(消息队列)的接口基于OpenHarmony的嵌入式开发30接口名称接口功能说明LOS_QueueCreate创建一个消息队列,由系统动态申请队列空间LOS_QueueDelete根据队列ID删除一个指定队列LOS_QueueRead读取指定队列头节点中的数据(队列节点中的数据实际上是一个地址)LOS_QueueWrite向指定队列尾节点中写入入参bufferAddr的值(即buffer的地址)LOS_QueueWriteHead向指定队列头节点中写入入参bufferAddr的值(即buffer的地址)LOS_QueueReadCopy读取指定队列头节点中的数据LOS_QueueWriteCopy向指定队列尾节点中写入入参bufferAddr中保存的数据LOS_QueueWriteHeadCopy向指定队列头节点中写入入参bufferAddr中保存的数据LOS_QueueInfoGet获取指定队列的信息,包括队列ID、队列长度、消息节点大小、头节点、尾节点、可读节点数量、可写节点数量、等待读操作的任务、等待写操作的任务安全边距3.1进程间通信[3.1.3]队列(Queue)队列(消息队列)的开发示例-基本流程

(1)通过LOS_QueueCreate接口创建队列,创建成功即可获得队列ID;

(2)通过LOS_QueueWrite或者LOS_QueueWriteCopy写队列;

(3)通过LOS_QueueRead或者LOS_QueueReadCopy读队列;

(4)通过LOS_QueueInfoGet获取队列信息;

(5)通过LOS_QueueDelete删除队列。队列(消息队列)的开发示例-注意事项

(1)系统支持的最大队列数指的是整个系统的队列资源的总个数,而非用户能使用的个数。

(2)创建队列时传入的队列名和flags暂时未使用,作为以后的预留参数。

(3)队列接口函数中的入参timeOut是相对时间。基于OpenHarmony的嵌入式开发31安全边距3.1进程间通信[3.1.3]队列(Queue)队列(消息队列)的开发示例-注意事项(4)LOS_QueueReadCopy和LOS_QueueWriteCopy及LOS_QueueWriteHeadCopy是一组接口,LOS_QueueRead和LOS_QueueWrite及LOS_QueueWriteHead是一组接口,每组接口需要配套使用。

(5)鉴于LOS_QueueWrite和LOS_QueueWriteHead和LOS_QueueRead这组接口实际操作的是数据地址,用户必须保证调用LOS_QueueRead获取到的指针所指向的内存区域在读队列期间没有被异常修改或释放,否则可能导致不可预知的后果。(6)LOS_QueueRead和LOS_QueueReadCopy接口的读取长度如果小于消息实际长度,消息将被截断。

(7)鉴于LOS_QueueWrite和LOS_QueueWriteHead和LOS_QueueRead这组接口实际操作的是数据地址,也就意味着实际写和读的消息长度仅仅是一个指针数据,因此用户使用这组接口之前,需确保创建队列时的消息节点大小,为一个指针的长度,避免不必要的浪费和读取失败。基于OpenHarmony的嵌入式开发32安全边距3.1进程间通信[3.1.3]队列(Queue)队列(消息队列)的应用示例

创建队列,两个任务。任务1SendEntry调用写队列接口发送消息,任务2RecvEntry通过读队列接口接收消息。执行流程如下。

(1)通过LOS_TaskCreate创建任务1SendEntry和任务2RecvEntry。

(2)通过LOS_QueueCreate创建一个消息队列。

(3)在任务1SendEntry中发送消息。

(4)在任务2RecvEntry中接收消息。

(5)通过LOS_QueueDelete删除队列。基于OpenHarmony的嵌入式开发33安全边距3.1进程间通信[3.1.3]队列(Queue)队列(消息队列)的应用示例-

ExampleQueue

基于OpenHarmony的嵌入式开发34#defineBUFFER_LEN50staticUINT32g_queue;UINT32ExampleQueue(VOID){

……;printf("startqueueexample.\n");

……;initParam.pfnTaskEntry=(TSK_ENTRY_FUNC)SendEntry;

initParam.usTaskPrio=9;

……;LOS_TaskLock();

ret=LOS_TaskCreate(&task1,&initParam);if(ret!=LOS_OK){printf("createtask1failed,error:%x\n",ret);returnret;}……;initParam.pfnTaskEntry=(TSK_ENTRY_FUNC)RecvEntry;initParam.usTaskPrio=10;

ret=LOS_TaskCreate(&task2,&initParam);if(ret!=LOS_OK){printf("createtask2failed,error:%x\n",ret);returnret;}

ret=LOS_QueueCreate("queue",5,&g_queue,0,50);if(ret!=LOS_OK){printf("createqueuefailure,error:%x\n",ret);}printf("createthequeuesuccess.\n");LOS_TaskUnlock();returnret;}externUINT32LOS_QueueCreate(constCHAR*queueName,UINT16len,UINT32*queueID,UINT32flags,UINT16maxMsgSize);安全边距3.1进程间通信[3.1.3]队列(Queue)队列(消息队列)的应用示例-

SendEntry和RecvEntry

基于OpenHarmony的嵌入式开发35VOIDSendEntry(VOID){UINT32ret=0;CHARabuf[]="testmessage";UINT32len=sizeof(abuf);

ret=LOS_QueueWriteCopy(g_queue,abuf,len,0);if(ret!=LOS_OK){printf("sendmessagefailure,error:%x\n",ret);}}VOIDRecvEntry(VOID){UINT32ret=0;CHARreadBuf[BUFFER_LEN]={0};UINT32readLen=BUFFER_LEN;usleep(1000000);

ret=LOS_QueueReadCopy(g_queue,readBuf,&readLen,0);if(ret!=LOS_OK){printf("recvmessagefailure,error:%x\n",ret);}printf("recvmessage:%s\n",readBuf);ret=LOS_QueueDelete(g_queue);if(ret!=LOS_OK){printf("deletethequeuefailure,error:%x\n",ret);}printf("deletethequeuesuccess.\n");}externUINT32LOS_QueueWriteCopy(UINT32queueID,VOID*bufferAddr,

UINT32bufferSize,UINT32timeOut);externUINT32LOS_QueueReadCopy(UINT32queueID,VOID*bufferAddr,

UINT32*bufferSize,UINT32timeOut);安全边距3.1进程间通信[3.1.3]队列(Queue)队列(消息队列)的应用示例-

SendEntry和RecvEntry

基于OpenHarmony的嵌入式开发36SendEntryret=LOS_QueueWriteCopy(g_queue,abuf,len,0);RecvEntryret=LOS_QueueReadCopy(g_queue,readBuf,

&readLen,0);//接收数据成功后printf("recvmessage:%s\n",readBuf);ret=LOS_QueueDelete(g_queue);//删除队列成功后printf("deletethequeuesuccess.\n");ExampleQueueprintf("startqueueexample.\n");ret=LOS_TaskCreate(&task1,&initParam);

//优先级9ret=LOS_TaskCreate(&task2,&initParam);

//优先级10ret=LOS_QueueCreate("queue",5,&g_queue,0,50);printf("createthequeuesuccess.\n");创建任务1和任务2任务1优先级为9(高),优先执行任务2优先级为10(低)课堂思考/讨论程序运行结果安全边距3.1进程间通信[3.1.3]队列(Queue)队列(消息队列)的应用示例-

SendEntry和RecvEntry

基于OpenHarmony的嵌入式开发37SendEntryret=LOS_QueueWriteCopy(g_queue,abuf,len,0);RecvEntryret=LOS_QueueReadCopy(g_queue,readBuf,

&readLen,0);//接收数据成功后printf("recvmessage:%s\n",readBuf);ret=LOS_QueueDelete(g_queue);//删除队列成功后printf("deletethequeuesuccess.\n");ExampleQueueprintf("startqueueexample.\n");ret=LOS_TaskCreate(&task1,&initParam);

//优先级9ret=LOS_TaskCreate(&task2,&initParam);

//优先级10ret=LOS_QueueCreate("queue",5,&g_queue,0,50);printf("createthequeuesuccess.\n");创建任务1和任务2任务1优先级为9(低)任务2优先级为10(高),优先执行程序运行结果如下startqueueexample.createthequeuesuccess.recvmessage:testmessage.deletethequeuesuccess.安全边距3.1进程间通信[3.1.4]信号量(Semaphore)

信号量(Semaphore)又称信号灯,是一种实现任务间通信的机制,可以实现任务间同步或共享资源的互斥访问。

在信号量的数据结构中,通常有一个计数值,用于对有效资源数的计数,表示剩下的可被使用的共享资源数,其值的含义分两种情况。

(1)0,表示该信号量当前不可获取,因此可能存在正在等待该信号量的任务。

(2)正值,表示该信号量当前可被获取。基于OpenHarmony的嵌入式开发38初始信号量计数值不为0,表示可用的共享资源个数。在需要使用共享资源前,先获取信号量,然后使用一个共享资源,使用完毕后释放信号量。这样在共享资源被取完,即信号量计数减至0时,其他需要获取信号量的任务将被阻塞,从而保证了共享资源的互斥访问。另外,当共享资源数为1时,建议使用二值信号量,一种类似于互斥锁的机制。初始信号量计数值为0。任务1因获取不到信号量而阻塞,直到任务2或者某中断释放信号量,任务1才得以进入Ready或Running态,从而达到了任务间的同步。安全边距3.1进程间通信[3.1.4]信号量(Semaphore)控制块:基于OpenHarmony的嵌入式开发39/***@ingrouplos_sem*Semaphorecontrolstructure.*/typedefstruct{

/**<Semaphorestate*/

UINT16semStat;

/**<Numberofavailablesemaphores*/

UINT16semCount;

/**<Maxnumberofavailablesemaphores*/UINT16maxSemCount;

/**<SemaphorecontrolstructureID*/

UINT16semID;

/**<Queueoftasksthatarewaitingonasemaphore*/LOS_DL_LISTsemList;}LosSemCB;LiteOS-M/LiteoS-A信号量控制块#defineOS_SEM_UNUSED0#defineOS_SEM_USED1安全边距3.1进程间通信[3.1.4]信号量(Semaphore)运行原理:多个任务在同一时刻访问共享资源,但会限制同一时刻访问此资源的最大任务数目。当任务数达到该资源允许的最大访问数量时,会阻塞其他试图获取该资源的任务,直到有任务释放该信号量。基于OpenHarmony的嵌入式开发40注意:与互斥锁的区别安全边距3.1进程间通信[3.1.4]信号量(Semaphore)信号量的接口基于OpenHarmony的嵌入式开发41接口名称接口功能说明LOS_SemCreateLOS_BinarySemCreate创建信号量或二值信号量,返回信号量ID。从未使用的信号量链表中获取一个信号量,并设定初值。LOS_SemDelete删除指定的信号量。将正在使用的信号量置为未使用信号量,并挂回到未使用链表。LOS_SemPend申请指定的信号量,并设置超时时间。若其计数器值大于0,则直接减1返回成功。否则任务阻塞,等待其它任务释放该信号量,等待的超时时间可设定。当任务被一个信号量阻塞时,将该任务挂到信号量等待任务队列的队尾。LOS_SemPost释放指定的信号量。若没有任务等待该信号量,则直接将计数器加1返回。否则唤醒该信号量等待任务队列上的第一个任务。安全边距3.1进程间通信[3.1.4]信号量(Semaphore)信号量的的应用示例:ExampleSem创建一个信号量,锁任务调度。然后创建两个任务ExampleSemTask1和ExampleSemTask2,其中,ExampleSemTask2的优先级高于ExampleSemTask1。两个任务申请同一信号量,解锁任务调度后,测试任务ExampleSem释放信号量。

(1)ExampleSemTask2得到信号量后被调度,然后

温馨提示

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

评论

0/150

提交评论