任务的同步与通信修改的--

整理文档很辛苦,赏杯茶钱您下走!

免费阅读已结束,点击下载阅读编辑剩下 ...

阅读已结束,您可以下载文档离线阅读编辑

资源描述

第三章任务管理3.3任务同步与通信3.2多任务3.1任务描述和状态,控制3.3任务的同步与通信1.任务的同步和事件2.事件控制块及事件处理函数3.信号量及其操作4.消息邮箱及其操作5.消息队列及其操作1.任务的同步和事件嵌入式系统中的各个任务是为同一个大的任务服务的子任务,它们不可避免地要共同使用一些共享资源,并且在处理一些需要多任务共同协作来完成的工作时,还需要相互的支持和限制。因此,对于一个完善的多任务操作系统来说,系统必须具有完备的同步和通信机制任务间的同步为了实现各个任务之间的合作和无冲突运行,在各任务之间必须建立一些约束关系直接制约关系间接制约关系任务间的同步-直接制约关系直接制约关系源于任务之间的合作例如:有任务A和任务B两个任务,他们需要访问同一个数据缓冲区合作完成一项任务任务A任务B缓冲区写入数据读出数据任务A为向缓冲区写入数据时,任务B因不能从缓冲区得到有效数据而应该处于等待状态只有等任务A向缓冲区写入了数据之后,才应该通知任务B去取数据当缓冲区的数据还未被任务B读取时,任务A就不能像缓冲区写入新的数据而应该处于等待状态只有等任务B自缓冲区读取数据后,才应该通知任务A写入数据任务间的同步-间接制约关系间接制约关系源于对资源的共享例如:任务A和任务B共享一台打印机任务A任务B打印机如果系统已经把打印机分配给任务A,则任务B因不能获得打印机的使用权而应该处于等待状态只有当任务A把打印机释放后,系统才能唤醒任务B使其获得打印机的使用权。因此,在多任务合作工作的过程中,操作系统应该解决两个问题:各任务间应该具有一种互斥关系,即对于某个共享资源,如果一个任务正在使用,则其他任务只能等待,等该任务释放该资源后,等待的任务之一才能使用它相关的任务在执行上要有先后次序,一个任务要等其伙伴发来通知,或建立了某个条件后才能继续执行,否则只能等待任务之间的这种制约性的合作运行机制叫做任务间的同步事件uC/os-II使用信号量,邮箱(消息邮箱)和消息队列这些中间环节来实现任务之间的通信。为了方便起见,这些中间环节都统一被称作“事件任务1任务2事件发送事件请求事件如上图:任务1是发信方,任务2是收信方作为发信方,任务1的责任是把信息发送到事件上,这项操作叫做发送事件作为收信方,任务2的责任是通过读事件操作对事件事件进行查询:如果有信息,则读取信息;否则等待。读事件操作叫做请求事件uC/os-II把任务发送事件,请求事件以及其他对事件的操作都定义成为全局函数,以供应用程序的所有任务来调用信号量信号量是一类事件。使用信号量的最初目的,是为了给共享资源设立一个标志,该标识表示该共享资源被占用的情况。这样,当一个任务在访问共享资源之前,就可以先对这个标志进行查询,从而在了解资源被占用的情况之后,再来决定自己的行为两个任务正在使用互斥型信号量进行通信任务1任务210信号量共享资源先请求信号量后请求信号量任务1在访问共享资源之前先进性请求信号量操作,当任务1发现信号量的标志为“1”时,它一方面把信号量的标志由“1”改为“0”,另一方面进行共享资源的访问任务2在任务1已经获得信号之后来请求信号量,那么由于它获得的标志值是“0”,所以任务2只能等待而不能访问共享资源任务1任务2010信号量共享资源发送信号量请求信号量任务1使用完共享资源之后,由任务1向信号量发信号使信号量标志的值由0变为1,任务2就有机会访问共享资源。任务2一旦获得了共享资源的访问权,那么在访问共享资源之前一定要把信号量标志值由1变为0消息邮箱在多任务操作系统中,常常需要在任务与任务之间通过传递一个数据(这种数据叫做“消息”)的方式来进行通信为了达到这个目的,可以在内存中创建一个存储空间作为该数据的缓冲区把这个缓冲区叫做消息缓冲区,在任务间传递数据一个最简单的方法就是传递消息缓冲区的指针。用来传递消息缓冲区指针的数据结构就叫做消息邮箱任务1任务2消息缓冲区指针消息邮箱发送消息(发送消息缓冲区指针)请求消息(读取消息缓冲区指针)消息队列上面谈到的消息邮箱不仅可以用来传递一个消息,而且可以定义一个指针数组。让数组的每个元素都存放一个消息缓冲区指针,那么任务就可通过传递这个指针数组指针的方法来传递多个消息了。这种可以传递多个消息的数据结构叫做消息队列任务1任务2消息缓冲区2消息缓冲区1消息缓冲区n指针消息队列.......发送消息队列(发送消息缓冲区指针数组的指针)请求消息队列(读取消息缓冲区指针数组的指针)2.事件控制块及事件处理函数对于事件来说,当一个事件被占用时,会导致其他请求该事件的任务因暂时得不到事件的服务而处于等待状态。作为功能完善的事件,应该对这些等待任务具有两方面的管理功能:一是要对等待事件的所有任务进行记录并排序二是应该允许等待任务有一个等待时限,即当任务认为等不及时可以退出对事件的请求对于等待事件任务的记录,uC/os-II又使用了与任务就绪表类似的位图,即定义了一个INT8U类型的数组OSEventTbl[]来作为等待事件任务的记录表,即等待任务表等待任务表仍然以任务的优先级别为顺序为每个任务分配一个二进制位,并用该位为“1”来表示这一位对应的任务位事件的等待任务,否则不是等待任务同样,为了加快对该表的访问速度,也定义了一个INT8U类型的变量OSEventGrp来表示等待任务表中的任务组。1/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/01/0OSEventGrp任务等待表OSEventTbl[]事件控制块的结构为了把描述事件的数据结构统一起来uC/os-II使用叫做事件控制块ECB的数据结构来描述诸如信号量,邮箱(消息邮箱)和消息队列这些事件typedefstruct{INT8UOSEventType;//事件的类型INT16UOSEventCnt;//信号量计数器void*OSEventPtr;//消息或消息队列的指针INT8UOSEventPtr;//等待事件的任务组INT8UOSEventTbl[OS_EVENT_TBL_SIZE];//事件等待表}操作事件控制块的函数uC/os-II有4个对事件控制块进行基本操作的函数(定义在文件OS_CORE.C),以供操作信号量,消息邮箱,消息队列等事件的函数来调用1.事件控制块初始化函数voidOS_EventWaitListInit(OS_EVENT*pevent//事件控制块指针);函数作用:把变量OSEventGrp及任务等待表中的每一位都清0,即令事件的任务等代表中不含任何等待任务2.使一个任务进入等待状态的函数voidOS_EventTaskWait(OS_EVENT*pevent//事件控制块指针);将在任务调用函数OS***Pend()请求一个事件时被函数OS***Pend()所调用3.使一个正在等待的任务进入就绪状态INT8UOS_EventTaskRdy(OS_EVENT*pevent,//事件控制块指针void*msg,//未使用INT8Umsk//清除TCB状态标志掩码);将在任务调用函数OS***Post()发送一个事件时被函数OS***Post()调用4.使一个等待超时的任务进入就绪状态voidOS_EventTO(OS_EVENT*pevent//事件控制块指针);如果一个正在等待事件的任务已经超过了等待的时间,却仍因为没有获取事件等原因而为具备可以运行的条件,却又要使他进入就绪状态,这是调用函数OS_EventTO()3.信号量及其操作1.创建信号量OS_EVENT*OSSemCreate(INT16Ucnt//信号量计数器初始值);返回值为已创建的信号量的指针2.请求信号量voidOSSemPend(OS_EVENT*pevent,//信号量的指针INT16Utimeout,//等待时限INT8U*err//错误信息);为防止任务因得不到信号量而处于长期的等待状态,函数允许参数timeout设置一个等待事件的限制。当任务等待事件超过timeout,可以结束等待状态而进入就绪状态。如果该参数设置为0,表明任务的等待时间为无限长函数调用成功后,err的值为OS_NO_ERR.如果函数调用失败,则函数会根据在函数中出现的具体错误,令err的值分别为OS_ERR_PEND_ISR,OS_ERR_PEVENT_NULL,OS_ERR_EVENT_TYPE和OS_TIMEOUT当任务需要访问一个共享资源时,先要请求管理该资源的信号量,这时就可以根据信号量当前是否有效(即信号量计数器OSEventCnt是否大于0)来决定该任务是否可以继续运行如果信号量有效,则把信号量计数器-1,然后继续运行任务如果无效,则会在等待任务表中对应的位置1而让任务处于等待状态,并把等待时限timeout保存在TCB的OSTCBDly中当一个任务请求信号量时,如果希望在信号量无效时准许任务不进入等待状态而继续运行,则调用OSSemAccept()INT16UOSSemAccept(OS_EVENT*pevent,//信号量的指针);3.发送信号量任务获得信号量,并在访问共享资源结束后,必须释放信号量。释放信号量也叫做发送信号量。发送信号量调用OSSemPost().该函数在对信号量计数器操作之前,首先要检查是否还有等待该信号量的任务;如果没有,则将该信号量计数器OSEventCnt+1;如果有,则调用调度器OS_Sched()去运行等待任务中优先级最高的任务INT8UOSSemPost(OS_EVENT*pevent,//信号量的指针);4.删除信号量OS_EVENT*OSSemDel(OS_EVENT*pevent,//信号量的指针INT8Uopt,//删除条件选项INT8U*err//错误信息);函数中的参数opt用来指明信号量的删除条件。该参数有两个值可以选择:OS_DEL_NO_PEND:当等待任务列表中没有等待任务时删除信号量OS_DEL_ALLWAYS:无论等待任务列表中是否有等待任务都删除信号量函数调用成功后,err值为OS_NO_ERR需要注意的是,只能在任务中删除信号量,而不能在中断服务程序中删除5.查询信号量的状态INT8UOSSemQuery(OS_EVENT*pevent,//信号量的指针OS_SEM_DATA*pdata//存储信号量状态的结构);任务调用函数对信号量查询会,会把信号量中的相关信息存储到OS_SEM_DATA类型的变量中,因此调用该函数之前,须定义一个OS_SEM_DATA结构类型的变量函数调用成功后,返回值为OS_NO_ERR4.消息邮箱及其操作消息邮箱通过在两个需要的任务之间传递数据缓冲区指针来进行通信1.创建消息邮箱OS_EVENT*OSMboxCreate(void*msg//消息指针)函数返回消息邮箱指针2.向消息邮箱发送信息INT8UOSMboxPost(OS_EVENT*pevent,//消息邮箱指针void*msg//消息指针);其中第二个参数为消息缓冲区指针;函数返回值未错误号INT8UOSMboxPostOpt(OS_EVENT*pevent,//消息邮箱指针void*msg,//消息指针INT8Uopt//广播选项);该函数可以用广播的方式向事件等待任务表中所有任务发送消息3.请求消息邮箱void*OSMboxPend(OS_EVENT*peve

1 / 70
下载文档,编辑使用

©2015-2020 m.777doc.com 三七文档.

备案号:鲁ICP备2024069028号-1 客服联系 QQ:2149211541

×
保存成功