FreeRTOS 第十7章 互斥量

互斥量和二值量很像。但是有区别,比如,二值量被获取了,别的任务就不能获取该信号量了,但是别的任务可以向其释放信号量,而互斥量是由谁获取就由谁释放,而且持有该信号量的也能再次获取信号量,也就是互斥递归量,而一般的信号量获取了没有了,再次获取可能会引起阻塞。为实现同步,二值信号量是更好的选择,互斥量更多的用于资源保护,而且它通过优先级继承算法降低了优先级翻转造成的影响。

优先级继承机制:暂时提高当前获得资源的任务的优先级到阻塞列表中最高等级优先级。

优先级翻转:高优先级任务因不能抢占低优先级的执行,而必须等待低优先级任务释放信号量,造成一个假象“高优先级反而在等待低优先级任务的执行”。并且,如果低优先级任务在获得临界资源运行中,并且高优先级任务因渴望获得资源而阻塞时,突然一个中等优先级任务解除阻塞加入就绪列表,其不需要该资源,它就有可能抢占低优先级任务,使得高优先级任务需要等待时间为,低优先级任务运行时间+中等优先级任务运行时间。优先级继承机制是当一个更高优先级任务提出申请时,把获得互斥量的任务的优先级提高到与提出申请的任务相同的等级(并不是所有任务的最高,只是提出申请的任务做高等级),使得它们二者之间的优先级不能打断它,这样那个渴望获得资源的高优先级任务的等待时间最少。但是只是说尽量使等待时间最少,但是还是必须得等到别人用完了才能使用。

互斥量常用于任务之中,而不能用于中断中,毕竟中断不是任务,它不能提高中断优先级。

互斥量也是依靠消息队列实现,有些许不一样

  union	
	{
		int8_t *pcReadFrom;		//消息队列读位置	
		UBaseType_t uxRecursiveCallCount;  //记录递归互斥量的调用次数
	} u;

//为消息队列时表示消息数目,为互斥量时表示互斥量的有效个数,1有效,0无效
volatile UBaseType_t uxMessagesWaiting;
//互斥量时表示最大可用信号量
	UBaseType_t uxLength;			
//为0
	UBaseType_t uxItemSize;	

普通互斥量

其创建函数是个宏定义

#define xSemaphoreCreateMutex() 
        xQueueCreateMutex( queueQUEUE_TYPE_MUTEX )

宏定义展开传入的参数是queueQUEUE_TYPE_MUTEX,而这个函数源码也是调用的xQueueGenericCreate(),同时还调用了初始化互斥量函数prvInitialiseMutex()函数。在这个初始化函数中,如果用作普通的互斥量,也就是只有有效和无效,那么

pxNewQueue->u.uxRecursiveCallCount = 0 ;//联合体中的变量递归次数设为0,如果是递归互斥量,就要重新赋值,当然由其它的函数来创建。

查看之前消息队列的初始化函数在哪里,它是被定义在xQueueGenericCreate()下面的,可见当创建互斥量时,递归互斥量也被当做普通的消息队列给初始化一次了,但是退出xQueueGenericCreate()后,又再次调用prvInitialiseMutex()把它初始化为互斥量。

递归互斥量

#define xSemaphoreGiveRecursive( xMutex )	
        xQueueGiveMutexRecursive( ( xMutex ) )

也是宏定义

互斥量删除函数之前讲了用xSemaphoreDelete()

互斥量获取函数xSemaphoreTake() 展开也是调用的xQueueGenericReceive()函数,只不过通过条件编译以及传入的参数是queueQUEUE_TYPE_MUTEX,通过一个判断传入的参数是不是queueQUEUE_TYPE_MUTEX使得这个互斥量的获取函数和之前的消息队列获取函数不一样,增加了一些代码,就先获得任务的TCB,为后面提高优先级做准备,然后调用一个优先级继承函数,就是判断提出获取互斥量要求的函数和当前拥有的互斥量的任务的优先级谁高,如果是提出申请的更高,就会提高当前拥有互斥量的任务的优先级,使得等待时间更少,更具体还区分了持有互斥量的是不是在就绪列表或者事件列表。

递归互斥量获取函数xSemaphoreTakeRecursive()

#define xSemaphoreTakeRecursive( xMutex, xBlockTime )	
        xQueueTakeMutexRecursive( ( xMutex ), ( xBlockTime ) )

看看xQueueTakeMutexRecursive( ( xMutex ), ( xBlockTime ) ) 函数,它的函数中就是一个if-else结构,如果提出申请的是当前正在拥有互斥量的任务,那么只需要把结构体中联合体的变量uxRecursiveCallCount加一,如果不是(互斥量不被谁占有或者已被占用,但是该次申请不是由获得互斥量的任务提出),则去执行xQueueGenericReceive函数,获取成功了,则把uxRecursiveCallCount加一,没有获取成功,就去阻塞。

互斥量释放函数xSemaphive()其实就底层就是把uxMessagesWaiting加一,以及恢复任务的优先级,然后设置pxMutexHolder设置为null,解除阻塞任务,执行任务调度.

xSemaphoreGiveRecursive(),调用多少次就要释放多少次,且必须释放完了,才有效,当uxRecursiveCallCount变为0时候,才能开锁,然后调用一个xQueueGenericSend(),它使得互斥量真正变为有效(消息队列发送函数),使得互斥量被其它任务申请,同时解除等待带互斥量的任务,调整其优先级到初始优先级。可见,互斥量本质还是严重依赖消息队列,只是个别参数的用法变了,代表的意义不同了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值