首页 > 其他分享 >FreeRTOS--递归锁

FreeRTOS--递归锁

时间:2023-12-17 16:56:00浏览次数:33  
标签:FreeRTOS 递归 -- configUSE xReturn pxMutex uxRecursiveCallCount RECURSIVE

示例源码基于FreeRTOS V9.0.0

递归锁

1. 概述

递归锁是特殊的互斥量,允许同一任务多次获取和释放锁,而不会造成死锁;

获取和释放的次数必须相同;

递归锁的实现依赖于内部的uxRecursiveCallCount变量,它标记递归的次数,每次上锁加1,每次解锁减1,减为0才真正释放锁;

递归锁也不能在中断内使用;

使用递归锁需开启configUSE_RECURSIVE_MUTEXES宏。

2. 接口API

2.1 创建递归锁

// 动态创建
#if( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configUSE_RECURSIVE_MUTEXES == 1 ) )
	#define xSemaphoreCreateRecursiveMutex() xQueueCreateMutex( queueQUEUE_TYPE_RECURSIVE_MUTEX )
#endif

// 静态创建
#if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configUSE_RECURSIVE_MUTEXES == 1 ) )
	#define xSemaphoreCreateRecursiveMutexStatic( pxStaticSemaphore ) xQueueCreateMutexStatic( queueQUEUE_TYPE_RECURSIVE_MUTEX, pxStaticSemaphore )
#endif /* configSUPPORT_STATIC_ALLOCATION */

参考FreeRTOS--互斥量 xQueueCreateMutex和xQueueCreateMutexStatic接口分析,递归锁和互斥量在创建时的差异仅为队列类型。

2.2 删除递归锁

#define vSemaphoreDelete( xSemaphore ) vQueueDelete( ( QueueHandle_t ) ( xSemaphore ) )

需注意,不能在任务持有信号量的时候使用vSemaphoreDelete接口删除信号量!!!

2.3 获取递归锁

#if( configUSE_RECURSIVE_MUTEXES == 1 )
	#define xSemaphoreTakeRecursive( xMutex, xBlockTime )	xQueueTakeMutexRecursive( ( xMutex ), ( xBlockTime ) )
#endif

使用宏xSemaphoreTakeRecursive获取递归锁,实际调用的是xQueueTakeMutexRecursive:

#if ( configUSE_RECURSIVE_MUTEXES == 1 )

    BaseType_t xQueueTakeMutexRecursive( QueueHandle_t xMutex, TickType_t xTicksToWait )
    {
    BaseType_t xReturn;
    Queue_t * const pxMutex = ( Queue_t * ) xMutex;

        configASSERT( pxMutex );

        /* Comments regarding mutual exclusion as per those within
        xQueueGiveMutexRecursive(). */

        traceTAKE_MUTEX_RECURSIVE( pxMutex );

        if( pxMutex->pxMutexHolder == ( void * ) xTaskGetCurrentTaskHandle() ) /*lint !e961 Cast is not redundant as TaskHandle_t is a typedef. */
        {
            ( pxMutex->u.uxRecursiveCallCount )++;
            xReturn = pdPASS;
        }
        else
        {
            xReturn = xQueueGenericReceive( pxMutex, NULL, xTicksToWait, pdFALSE );

            /* pdPASS will only be returned if the mutex was successfully
            obtained.  The calling task may have entered the Blocked state
            before reaching here. */
            if( xReturn != pdFAIL )
            {
                ( pxMutex->u.uxRecursiveCallCount )++;
            }
            else
            {
                traceTAKE_MUTEX_RECURSIVE_FAILED( pxMutex );
            }
        }

        return xReturn;
    }

#endif /* configUSE_RECURSIVE_MUTEXES */
  • 如果是当前任务已经持有了递归锁,则累加递归次数(uxRecursiveCallCount),并返回pdPASS;

  • 如果是其他任务持有,或者没人持有,调用xQueueGenericReceive尝试获取,如果获取成功,累加递归次数(uxRecursiveCallCount),并返回pdPASS,否则返回xQueueGenericReceive返回值;

xTaskGetCurrentTaskHandle返回了当前任务块TCB指针,定义在task.c,实现如下:

#if ( ( INCLUDE_xTaskGetCurrentTaskHandle == 1 ) || ( configUSE_MUTEXES == 1 ) )

	TaskHandle_t xTaskGetCurrentTaskHandle( void )
	{
	TaskHandle_t xReturn;

		/* A critical section is not required as this is not called from
		an interrupt and the current TCB will always be the same for any
		individual execution thread. */
		xReturn = pxCurrentTCB;

		return xReturn;
	}

#endif /* ( ( INCLUDE_xTaskGetCurrentTaskHandle == 1 ) || ( configUSE_MUTEXES == 1 ) ) */

2.4 释放递归锁

#if( configUSE_RECURSIVE_MUTEXES == 1 )
	#define xSemaphoreGiveRecursive( xMutex )	xQueueGiveMutexRecursive( ( xMutex ) )
#endif
#if ( configUSE_RECURSIVE_MUTEXES == 1 )

    BaseType_t xQueueGiveMutexRecursive( QueueHandle_t xMutex )
    {
    BaseType_t xReturn;
    Queue_t * const pxMutex = ( Queue_t * ) xMutex;

        configASSERT( pxMutex );

        /* If this is the task that holds the mutex then pxMutexHolder will not
        change outside of this task.  If this task does not hold the mutex then
        pxMutexHolder can never coincidentally equal the tasks handle, and as
        this is the only condition we are interested in it does not matter if
        pxMutexHolder is accessed simultaneously by another task.  Therefore no
        mutual exclusion is required to test the pxMutexHolder variable. */
        if( pxMutex->pxMutexHolder == ( void * ) xTaskGetCurrentTaskHandle() ) /*lint !e961 Not a redundant cast as TaskHandle_t is a typedef. */
        {
            traceGIVE_MUTEX_RECURSIVE( pxMutex );

            /* uxRecursiveCallCount cannot be zero if pxMutexHolder is equal to
            the task handle, therefore no underflow check is required.  Also,
            uxRecursiveCallCount is only modified by the mutex holder, and as
            there can only be one, no mutual exclusion is required to modify the
            uxRecursiveCallCount member. */
            ( pxMutex->u.uxRecursiveCallCount )--;

            /* Has the recursive call count unwound to 0? */
            if( pxMutex->u.uxRecursiveCallCount == ( UBaseType_t ) 0 )
            {
                /* Return the mutex.  This will automatically unblock any other
                task that might be waiting to access the mutex. */
                ( void ) xQueueGenericSend( pxMutex, NULL, queueMUTEX_GIVE_BLOCK_TIME, queueSEND_TO_BACK );
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }

            xReturn = pdPASS;
        }
        else
        {
            /* The mutex cannot be given because the calling task is not the
            holder. */
            xReturn = pdFAIL;

            traceGIVE_MUTEX_RECURSIVE_FAILED( pxMutex );
        }

        return xReturn;
    }

#endif /* configUSE_RECURSIVE_MUTEXES */
  • 如果是当前任务已经持有了递归锁,则递减递归次数(uxRecursiveCallCount),然后检查递归次数是否归0,是的话,调用xQueueGenericSend释放锁。不管计数是否归0,都返回pdPASS;

  • 如果是其他任务持有,或者没人持有,则返回pdFAIL;

标签:FreeRTOS,递归,--,configUSE,xReturn,pxMutex,uxRecursiveCallCount,RECURSIVE
From: https://www.cnblogs.com/hjx168/p/17909304.html

相关文章

  • 实验6 模板类、文件I/O和异常处理
    实验任务1Complex.hpp#pragmaonce#include<iostream>#include<stdexcept>template<typenameT>classComplex{public:Complex(Tr=0,Ti=0):real{r},imag{i}{}Complex(constComplex<T>&c):real{c.real},imag{c.......
  • Codeforces Round 867 (Div. 3)
    CodeforcesRound867(Div.3)A:ABCD(E差一点点,最后把那种特殊情况想出来然后没写上去就结束了)A.TubeTubeFeed题意:给两个数组分别是时间和价值,要价值最大但是只能选一个思路:最开始以为是01背包,结果只选一个,一个一个枚举就行#include<bits/stdc++.h>usingnamespace......
  • Codeforces Round 855 (Div. 3)
    CodeforcesRound855(Div.3)A.IsItaCat?题意:要求:字符串必须以只包含字母"m"或"M"的非空序列开始必须紧跟由'e'或'E'字符组成的非空序列必须紧接着仅由字符'o'或'O'组成的非空序列必须紧接着是仅由字符'w'或'W'组成的非空序列思路:一个一个来(WA了三发注意这几......
  • 团队总结(五):冲刺总结(day 7)
    一、用户1.权限注册登记个人账号起草、修改、发布、接收、管理公文确定公文密级2.功能二、系统管理员gitee代码链接:https://gitee.com/an-jiran/dzgwxt/tree/master/用户界面管理员界面......
  • Codeforces Round 913 (Div. 3)
    CodeforcesRound913(Div.3)A:ABCA.Rook简单题,就两个循环搞定(直接上码)#include<bits/stdc++.h>usingnamespacestd;voidsolve(){chara;intb;cin>>a>>b;for(inti=1;i<=8;i++){if(i!=b){......
  • Codeforces Round 863 (Div. 3)
    CodeforcesRound863(Div.3)A.InsertDigit题意:插入一个字母使得这个数字最大化思路:只要从前往后便利就行#include<iostream>usingnamespacestd;voidsolve(){intn,k;cin>>n>>k;boolx=true,y=false;for(inti=0;i<n;i++){......
  • 20211105李宜时个人贡献
    个人分工一、个人工作简述1.需求规格说明书阶段界面原型和采访登录界面注册界面扫码登录团队介绍用户管理用户注册2.具体操作时期的任务框架建设阶段情况前端设计调试和修改阶段情况公文上传签收前端修改公文查询,签收二、代码链接发送公文页......
  • FreeRTOS--互斥量
    示例源码基于FreeRTOSV9.0.0互斥量1.概述互斥量用于临界资源的保护,通过互斥量,多个任务对相同资源进行的访问操作是互斥的;互斥量的核心在于谁上锁,就由谁解锁,这只是约定,FreeRTOS并没有在代码上实现这一点;互斥量是一种特殊的信号量,也是一种特殊的队列;使用互斥量,需要开启宏con......
  • docker从0安装Jenkins
    docker从0安装JenkinsUbuntu初始化sudoapt-getinstallopenssh-serversudovim/etc/ssh/sshd_config设置静态IPcd/etc/netplan···network:version:2renderer:NetworkManagerethernets:ens33:#网卡名称dhcp4:no#关闭dhcp......
  • SiReN Sign-Aware Recommendation Using Graph Neural Networks论文阅读笔记
    Abstract目前使用GNN的推荐系统主要利用高评分的正向用户-物品交互信息。但是如何利用低评分来表示用户的偏好是一个挑战,因为低评分仍然可以提供有用的信息。所以在本文中提出了基于GNN模型的有符号感知推荐系统SiReN,SiReN有三个关键组件构造一个符号二部图更精确的表示用户的......