基于STM32结合CubeMX学习Free-RT-OS的源码之信号量与互斥量
创始人
2024-01-21 05:25:57
0

目录

CUBEMX上的配置以及使用

信号量

互斥量


CUBEMX上的配置以及使用

信号量与互斥量都是从队列中衍生出来的,他们是一种特殊的队列。不同的地方在于:他们不含有队列的数据部分,只有队列结构体。 

定义属性(这里只有一个名字)和创建

信号量

 信号量又分二值信号量和计数信号量,本质上都是是资源可用的个数。

二值信号量只有0和1两个值。

二值信号量的创建  ( 参数部分为 队列长度为1(也就是计数值),数据成员类型大小为 0,队列类型为信号量类型)

#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )

    #define xSemaphoreCreateBinary() xQueueGenericCreate( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, queueQUEUE_TYPE_BINARY_SEMAPHORE )

#endif

pxQueue->uxMessagesWaiting     //在队列里现有数据个数,在信号量里则是计数值。

 //二值信号量则这个值只有 0 或 1

数据部分为0然后调用创建队列的哪一套库函数。(初始化了等待发送信号量链表,等待接受信号链接,这和队列里的等待读与等待写是一样的),以及主要的超时阻塞与任务的唤醒也一样。

经过源码发现,FREE RT OS重命名了获取信号量的函数

BaseType_t xQueueSemaphoreTake( QueueHandle_t xQueue, TickType_t xTicksToWait )

然而  释放信号量还是通过宏调用通用的队列写数据的方法

超时阻塞与任务唤醒参考

基于STM32结合CubeMX学习Free-RT-OS的源码之消息队列_昊月光华的博客-CSDN博客

互斥量

本文主要还是学习互斥量。

为什么?因为它有优先级继承这一特殊的机制防止优先级反转。

在操作系统的日常任务中,有些操作看起来只有一步,但在汇编代码中却有好几步!在抢占式得实时操作系统中,比如有多个任务对同一个值进行写回操作,则必须要求对该值操作时互斥。

为什么要互斥?

任务1: a++;

任务2 :a++

试想进行这两个任务,尽管我的STM32F1是一个只能单核运行的CPU,但是任务是会抢占的,抢占的同时,保留现场,当前任务的变量值入栈。

任务1运行,a++  。(从汇编上看分三步,第一步将内存里a的值取出装载到寄存器,第二步,该寄存器的值自增1,第三步写回)

若在a++执行的第三步写回之前被任务2抢占则会发生:

1:任务1的a的值(未写回)入栈。

2: sp(此时指向psp)指针切换任务2函数入口开始执行a++,由于上一个任务a还没有写回,a++执行并写回a为1。任务2执行完毕再恢复任务1的现场,a的值从栈中取出为0,这时候执行a++则a为1再写回。这样就导致了丢失修改。

这种情况下,如何解决,把a定义成__IO  也就是volatile 能解决这个丢失修改的问题。

volatile是一个特征修饰符(type specifier)。volatile的作用是作为指令关键字,确保本条指令不会因编译器的优化而省略,且要求每次直接读值。 

简单地说:编译器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份

我们知道,从内存里读取与从寄存器里读取的速度效率是不同的,寄存机效率大于内存。

使用互斥量则可以很好地解决在使用临界资源互斥的问题。

创建互斥量

 

 

递归互斥量与普通互斥量的区别:

  • 递归互斥量可以多次获取锁,并获取多少次锁就必须释放多少次锁。并规定由谁获取锁就又谁解锁。
  • 普通互斥量,只能获取一次锁,可以让不同的任务获取锁和释放锁(易造成死锁局面,最好是成对存在。)

释放和获取调用的是信号量的API,在函数内部对互斥量的情形进行判断。

获取互斥锁

     xSemaphoreTake(USEESPMUTEXHandle,portMAX_DELAY);

 xTaskPriorityInherit                             //优先级继承

 当高优先级的任务获取互斥锁时会干以下事情:

若是能获取锁(队列里的计数值为1)则减1为0。互斥量的队列头部记录当前持有互斥量的任务。

若无法获取锁,且超时阻塞等待获取锁时(把自己放入互斥量的等待读链表中),则进行判断当前获取互斥量的任务的优先级是否大于持有互斥量的任务的优先级,若是,则继承当前任务(高优先级)的优先级,同时再次判断持有互斥量的任务是否就绪,若是则加入被继承的优先级的就绪链表中,防止在两者优先级之间的任务插队。这就是优先级继承,防止了优先级的反转。

当继承了高优先级的低优先级的任务一旦释放了互斥量,若高优先级任务还在等待,则唤醒高优先级的任务,自己则恢复为原来的优先级,并把自己由于继承高优先级所在的高优先级链表移除并移动到原来的优先级链表。(相当于高优先级体验卡体验结束)。

 

BaseType_t xTaskPriorityInherit( TaskHandle_t const pxMutexHolder ){TCB_t * const pxMutexHolderTCB = ( TCB_t * ) pxMutexHolder;BaseType_t xReturn = pdFALSE;/* If the mutex was given back by an interrupt while the queue waslocked then the mutex holder might now be NULL.  _RB_ Is this stillneeded as interrupts can no longer use mutexes? */if( pxMutexHolder != NULL ){/* If the holder of the mutex has a priority below the priority ofthe task attempting to obtain the mutex then it will temporarilyinherit the priority of the task attempting to obtain the mutex. */if( pxMutexHolderTCB->uxPriority < pxCurrentTCB->uxPriority ){/* Adjust the mutex holder state to account for its newpriority.  Only reset the event list item value if the value isnot being used for anything else. */if( ( listGET_LIST_ITEM_VALUE( &( pxMutexHolderTCB->xEventListItem ) ) & taskEVENT_LIST_ITEM_VALUE_IN_USE ) == 0UL ){listSET_LIST_ITEM_VALUE( &( pxMutexHolderTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) pxCurrentTCB->uxPriority ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */}else{mtCOVERAGE_TEST_MARKER();}/* If the task being modified is in the ready state it will needto be moved into a new list. */if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ pxMutexHolderTCB->uxPriority ] ), &( pxMutexHolderTCB->xStateListItem ) ) != pdFALSE ){if( uxListRemove( &( pxMutexHolderTCB->xStateListItem ) ) == ( UBaseType_t ) 0 ){taskRESET_READY_PRIORITY( pxMutexHolderTCB->uxPriority );}else{mtCOVERAGE_TEST_MARKER();}/* Inherit the priority before being moved into the new list. */pxMutexHolderTCB->uxPriority = pxCurrentTCB->uxPriority;prvAddTaskToReadyList( pxMutexHolderTCB );}else{/* Just inherit the priority. */pxMutexHolderTCB->uxPriority = pxCurrentTCB->uxPriority;}traceTASK_PRIORITY_INHERIT( pxMutexHolderTCB, pxCurrentTCB->uxPriority );/* Inheritance occurred. */xReturn = pdTRUE;}else{if( pxMutexHolderTCB->uxBasePriority < pxCurrentTCB->uxPriority ){/* The base priority of the mutex holder is lower than thepriority of the task attempting to take the mutex, but thecurrent priority of the mutex holder is not lower than thepriority of the task attempting to take the mutex.Therefore the mutex holder must have already inherited apriority, but inheritance would have occurred if that hadnot been the case. */xReturn = pdTRUE;}else{mtCOVERAGE_TEST_MARKER();}}}else{mtCOVERAGE_TEST_MARKER();}return xReturn;}

释放互斥锁

   xSemaphoreGive(USEESPMUTEXHandle);

 xTaskPriorityDisinherit                               //优先级取消继承(恢复为原来的优先级)

	BaseType_t xTaskPriorityDisinherit( TaskHandle_t const pxMutexHolder ){TCB_t * const pxTCB = ( TCB_t * ) pxMutexHolder;BaseType_t xReturn = pdFALSE;if( pxMutexHolder != NULL ){/* A task can only have an inherited priority if it holds the mutex.If the mutex is held by a task then it cannot be given from aninterrupt, and if a mutex is given by the holding task then it mustbe the running state task. */configASSERT( pxTCB == pxCurrentTCB );configASSERT( pxTCB->uxMutexesHeld );( pxTCB->uxMutexesHeld )--;/* Has the holder of the mutex inherited the priority of anothertask? */if( pxTCB->uxPriority != pxTCB->uxBasePriority ){/* Only disinherit if no other mutexes are held. */if( pxTCB->uxMutexesHeld == ( UBaseType_t ) 0 ){/* A task can only have an inherited priority if it holdsthe mutex.  If the mutex is held by a task then it cannot begiven from an interrupt, and if a mutex is given by theholding task then it must be the running state task.  Removethe holding task from the ready list. */if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 ){taskRESET_READY_PRIORITY( pxTCB->uxPriority );}else{mtCOVERAGE_TEST_MARKER();}/* Disinherit the priority before adding the task into thenew	ready list. */traceTASK_PRIORITY_DISINHERIT( pxTCB, pxTCB->uxBasePriority );pxTCB->uxPriority = pxTCB->uxBasePriority;/* Reset the event list item value.  It cannot be in use forany other purpose if this task is running, and it must berunning to give back the mutex. */listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) pxTCB->uxPriority ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */prvAddTaskToReadyList( pxTCB );/* Return true to indicate that a context switch is required.This is only actually required in the corner case wherebymultiple mutexes were held and the mutexes were given backin an order different to that in which they were taken.If a context switch did not occur when the first mutex wasreturned, even if a task was waiting on it, then a contextswitch should occur when the last mutex is returned whethera task is waiting on it or not. */xReturn = pdTRUE;}else{mtCOVERAGE_TEST_MARKER();}}else{mtCOVERAGE_TEST_MARKER();}}else{mtCOVERAGE_TEST_MARKER();}return xReturn;}

在释放互斥锁时判断此任务是否有继承过高优先级的任务, 

if( pxTCB->uxPriority != pxTCB->uxBasePriority )

若是则恢复为原优先级, 并把自己从高优先级的链表中移除,加入到自己原来的优先级链表中。

若是一个高优先级的任务阻塞超时,低优先级的任务继承后,被更高优先级的任务抢占,则高优先级的任务在获取互斥量时判断超时后调用取消优先级继承函数。低优先级的继承体验卡只在高优先级阻塞时有效。

void vTaskPriorityDisinheritAfterTimeout( TaskHandle_t const pxMutexHolder, UBaseType_t uxHighestPriorityWaitingTask )

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
一帆风顺二龙腾飞三阳开泰祝福语... 本篇文章极速百科给大家谈谈一帆风顺二龙腾飞三阳开泰祝福语,以及一帆风顺二龙腾飞三阳开泰祝福语结婚对应...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...
美团联名卡审核成功待激活(美团... 今天百科达人给各位分享美团联名卡审核成功待激活的知识,其中也会对美团联名卡审核未通过进行解释,如果能...