本帖最后由 forgot 于 2022-11-22 09:39 编辑
在ucos常使用共享资源来作为任务之间的通信方式,其中有:消息队列,信号量,邮箱,事件。信号量中又分二值信号,多值信号,互斥信号。二值信号量作用:任务通过OSSemPend() 函数获得一个信号量,如果信号量有效(不为0),则任务继续运行,否则进入等待状态(挂起)。互斥信号量作用:任务通过OSMutexPend()函数获得互斥信号量,如果互斥信号有效(不为0)则继续运行,否则进入等待。
在ucos系统中信号量常用于任务的同步,通过该信号,就能够控制某个任务的执行,这个信号具有计数值,因此,可以称为计数信号量。 计数信号量可以用于资源管理,允许多个任务获取信号量访问共享资源,但会限制任务的最大数目。访问的任务数达到可支持的最大数目时,会阻塞其他试图获取该信号量的任务,直到有任务释放了信号量。这就是计数型信号量的运作机制,虽然计数信号量允许多个任务访问同一个资源,但是也有限定,比如某个资源限定只能有3个任务访问,那么第4个任务访问的时候,会因为获取不到信号量而进入阻塞,等到有任务(比如任务1)释放掉该资源的时候,第4个任务才能获取到信号量从而进行资源的访问。
使用信号量有可能导致一个严重的问题——优先级翻转: 优先级翻转是当一个高优先级任务通过信号量机制访问共享资源时,该信号量已被一低优先级任务占有,因此造成高优先级任务被许多具有较低优先级任务阻塞,实时性难以得到保证。
为了避免优先级翻转这个问题,UCOS支持一种特殊的二进制信号量:互斥信号量,即互斥锁,用它可以解决优先级翻转问题,具体函数:
如:三个用户任务,设置优先级为高、中、低,按照优先级命名函数,创建一个互斥信号量。
//信号量 OS_EVENT *mysem; mysem= OSMutexCreate(1);
//高优先级任务 void TaskHigh(void *p_arg) { u8 err; while(1) { OSMutexPend(mysem, 0, &err); ... OSMutexPost(mysem); OSTimeDly(1); } }
//中等优先级任务 void TaskMedium(void *pdata) { while(1) { ...
OSTimeDly(10); } }
//低优先级任务 void TaskLow(void *p_arg) { u8 err; while(1) { OSMutexPend(mysem, 0, &err); ... OSMutexPost(mysem); OSTimeDly(1); } }
由于采用的是互斥信号量OSMutexPend() 和OSMutexPost() ,所以把占用信号量任务的优先级给提高了。TaskLow任务在占用信号量期间,优先级会被提升,这样就不会被打断以便尽快运行完释放信号量,释放信号量后TaskLow任务优先级会恢复到原来的。
目前解决优先级翻转有许多种方法。其中普遍使用的有2种方法: 一种被称作优先级继承(priority inheritance); 另一种被称作优先级天花板(priority ceilings)。
优先级继承(priority inheritance) :优先级继承是指将低优先级任务的优先级提升到等待它所占有的资源的最高优先级任务的优先级。当高优先级任务由于等待资源而被阻塞时,此时资源的拥有者的优先级将会临时自动被提升,以使该任务不被其他任务所打断,从而能尽快的使用完共享资源并释放,再恢复该任务原来的优先级别。
优先级天花板(priority ceilings): 优先级天花板是指将申请某资源的任务的优先级提升到可能访问该资源的所有任务中最高优先级任务的优先级。(这个优先级称为该资源的优先级天花板) 。这种方法简单易行, 不必进行复杂的判断, 不管任务是否阻塞了高优先级任务的运行, 只要任务访问共享资源都会提升任务的优先级。
两种方式的区别: 优先级继承,只有当占有资源的低优先级的任务被阻塞时,才会提高占有资源任务的优先级;而优先级天花板,不论是否发生阻塞,都提升。
|