基本概念

  • 互斥量又称互斥信号量(本质是信号量),是一种特殊的二值信号量
  • 互斥量 支持互斥量所有权、递归访问以及防止优先级翻转的特性,用于实现对临界资源(如显示器、打印机)的独占式访问。
  • 任意时刻互斥量的状态只有两种,开锁或闭锁。
  • 持有该互斥量的任务也能够重复获得这个锁而不被挂起,这就是递归访问,也就是递归互斥量的特性,信号量重复获取则会被挂起
  • 互斥量与二值信号量最大的不同是:互斥量具有优先级继承机制,而信号量没有

优先级继承机制

  • 优先级继承算法是指,暂时提高某个占有某种资源的低优先级任务的优先级,使之和所有等待该资源的任务中优先级最高那个任务的优先级相等,而当这个低优先级任务执行完毕释放该资源时,优先级重新回到初始设定值
  • 优先级提升的过程叫做优先级继承

优先级翻转

高优先级任务无法运行而低优先级任务可以运行的现象称为“优先级翻转”

互斥量应用场景

  • 可能会引起优先级翻转的情况
  • 任务可能会多次获取互斥量的情况下。这样可以避免同一任务多次递归持有而造成死锁的问题
  • 多任务环境下往往存在多个任务竞争同一临界资源的应用场景,互斥量可被用于对临界资源的保护从而实现独占式访问
  • 例如串口资源的保护

函数

头文件

#include <semphr.h>

互斥量句柄

和消息队列一样

QueueHandle_t

控制块

互斥量控制块结构体与消息队列结构体是一模一样的,只不过结构体中某些成员变量代表的含义不一样而已

typedef struct QueueDefinition
{int8_t *pcHead;                    int8_t *pcTail;                 int8_t *pcWriteTo;              union                           {int8_t *pcReadFrom;            UBaseType_t uxRecursiveCallCount; //当结构体用于互斥量时,uxRecursiveCallCount 用于计数,记录递归互斥量被“调用”的次数} u;List_t xTasksWaitingToSend;       List_t xTasksWaitingToReceive;  volatile UBaseType_t uxMessagesWaiting;/* 这个值就表示有效互斥量个数,这个值是 1则表示互斥量有效,如果是 0 则表示互斥量无效*/UBaseType_t uxLength;          /*
如果控制块结构体被用于互斥量的时候,uxLength 表示最大的信号量可用个数,uxLength 最大为 1,因为信号量要么是有效的,要么是无效的*/UBaseType_t uxItemSize;          /*如果控制块结构体被用于互斥量的时候,则无需存储空间,为 0 即可。 */volatile int8_t cRxLock;        volatile int8_t cTxLock;        #if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )uint8_t ucStaticallyAllocated;  #endif#if ( configUSE_QUEUE_SETS == 1 )struct QueueDefinition *pxQueueSetContainer;#endif#if ( configUSE_TRACE_FACILITY == 1 )UBaseType_t uxQueueNumber;uint8_t ucQueueType;#endif} xQUEUE;

函数接口

创建互斥量xSemaphoreCreateMutex()

#define xSemaphoreCreateMutex() xQueueCreateMutex( queueQUEUE_TYPE_MUTEX )QueueHandle_t xQueueCreateMutex( const uint8_t ucQueueType )

递归互斥量创建函数 xSemaphoreCreateRecursiveMutex()

 #define xSemaphoreCreateRecursiveMutex() xQueueCreateMutex( queueQUEUE_TYPE_RECURSIVE_MUTEX )

互斥量删除函数 vSemaphoreDelete()

和信号量一样的函数

互斥量获取函数 xSemaphoreTake()

#define xSemaphoreTake( xSemaphore, xBlockTime )     xQueueGenericReceive( ( QueueHandle_t ) ( xSemaphore ), NULL, ( xBlockTime ), pdFALSE )
参数 说明
xSemaphore 信号量句柄
xBlockTime 等待信号量可用的最大超时时间,单位为 tick(即系统节拍周期)。如果宏 INCLUDE_vTaskSuspend 定义为 1 且形参xTicksToWait 设置为 portMAX_DELAY ,则任务将一直阻塞在该信号量上(即没有超时时间)
返回值 获 取 成 功 则 返 回 pdTRUE , 获取失败 返 回 errQUEUE_EMPTY。

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

 #define xSemaphoreTakeRecursive( xMutex, xBlockTime )   xQueueTakeMutexRecursive( ( xMutex ), ( xBlockTime ) )
/*。返回值                          获取成功则返回 pdTRUE,在超时之前没有获取成功则返回 errQUEUE_EMPTY。*/
参数 说明
xMutex 信号量句柄
xBlockTime 如果不是持有互斥量的任务去获取无效的互斥量,那么任务将进行等待用户指定 超时时间,单位 为 tick(即系统节拍周期) 。如果宏 INCLUDE_vTaskSuspend 定义为 1 且形参 xTicksToWait 设置为portMAX_DELAY ,则任务将一直阻塞在该递归互斥量上(即没有超时时间)。
返回值 获 取 成 功 则 返 回 pdTRUE , 获取失败 返 回 errQUEUE_EMPTY。

互斥量释放函数 xSemaphoreGive()


BaseType_t xSemaphoreGive(SemaphoreHandle_t  xSemaphore )   #define xSemaphoreGive( xSemaphore )        xQueueGenericSend( ( QueueHandle_t ) ( xSemaphore ), NULL, semGIVE_BLOCK_TIME, queueSEND_TO_BACK )
/*
如果信号量满,则返回错误代码(err_QUEUE_FULL)
*/

递归互斥量释放函数 xSemaphoreGiveRecursive()

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

示例:
之前2个任务的优先级一样,导致就是发送信号任务要打印,接收信号端不打印,引入锁后问题解决

#include "FreeRTOS.h"
#include "task.h"
#include<bsp_key.h>
#include "semphr.h"
#include <stdio.h>
/* USER CODE END Includes *//* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD *//* USER CODE END PTD *//* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD *//* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM *//* USER CODE END PM *//* Private variables ---------------------------------------------------------*//* USER CODE BEGIN PV *//* USER CODE END PV *//* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP *//* USER CODE END PFP *//* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
static TaskHandle_t send_Task_Handle = NULL;
static TaskHandle_t recv_Task_Handle = NULL;
static SemaphoreHandle_t xsem=NULL;
static SemaphoreHandle_t xlock=NULL;static void recv_Task(void * param)
{uint32_t data1;while (1){if(pdTRUE==xSemaphoreTake(xsem,portMAX_DELAY)){xSemaphoreTake(xlock,portMAX_DELAY );printf("take sem\r\n");xSemaphoreGive(xlock);HAL_GPIO_TogglePin(LED0_GPIO_Port, LED0_Pin);}}}static void send_Task(void * param)
{uint32_t data1=10;while (1){if(Key_Scan(KEY1_GPIO_Port,KEY1_Pin)==KEY_ON){xSemaphoreGive(xsem);xSemaphoreTake(xlock,portMAX_DELAY );printf("give sem\r\n");xSemaphoreGive(xlock);}vTaskDelay(100);}}/* USER CODE END 0 *//*** @brief  The application entry point.* @retval int*/
int main(void)
{/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_USART1_UART_Init();/* USER CODE BEGIN 2 */printf("hello FreeRTOS\r\n");//xqueue =  xQueueCreate(10, 4);xsem = xSemaphoreCreateBinary();xlock = xSemaphoreCreateMutex();if(xsem==NULL){printf("create queue fail\r\n");}BaseType_t        xReturn;xReturn             = xTaskCreate((TaskFunction_t) recv_Task, /* 任务入口函数 */(const char *) "recv_Task",                    /* 任务名字 */(uint16_t) 512,                               /* 任务栈大小 */(void *) NULL,                                   /* 任务入口函数参数 */(UBaseType_t) 2,                              /* 任务的优先级 */(TaskHandle_t *) &recv_Task_Handle);            /* 任务控制块指针 */xReturn            = xTaskCreate((TaskFunction_t) send_Task, /* 任务入口函数 */(const char *) "send_Task",                    /* 任务名字 */(uint16_t) 512,                               /* 任务栈大小 */(void *) NULL,                                   /* 任务入口函数参数 */(UBaseType_t) 2,                              /* 任务的优先级 */(TaskHandle_t *) &send_Task_Handle);            /* 任务控制块指针 */if (pdPASS == xReturn)vTaskStartScheduler(); /* 启动任务,开启调度 *//* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */HAL_GPIO_TogglePin(LED0_GPIO_Port, LED0_Pin);HAL_Delay(50);}/* USER CODE END 3 */
}

5.FreeRTOS学习笔记- 互斥量相关推荐

  1. FreeRTOS个人笔记-互斥量

    根据个人的学习方向,学习FreeRTOS.由于野火小哥把FreeRTOS讲得比较含蓄,打算在本专栏尽量细化一点.作为个人笔记,仅供参考或查阅. 配套资料:FreeRTOS内核实现与应用开发实战指南.野 ...

  2. FreeRTOS学习笔记——互斥型信号量

    来自:http://blog.csdn.net/xukai871105/article/details/43456985 0.前言 在嵌入式操作系统中互斥型信号量是任务间资源保护的重要手段.下面结合一 ...

  3. freertos 创建互斥量_STM32CubeMX+FreeRTOS学习[6] 互斥量(Lu)

    FreeRTOS 学习之六:互斥量 前提:默认已经装好 MDK V5 和 STM32CubeMX ,并安装了 STM32F1xx 系列的支持包. 硬件平台: STM32F1xx 系列. 目的:学习互斥 ...

  4. RT-Thread学习笔记——互斥量

    前言 前面学习了RT-Thread的信号量,但信号量在一些场合使用会存在优先级翻转问题,接下来我们学习互斥量,在 RT-Thread 操作系统中,互斥量可以解决优先级翻转问题,实现的是优先级继承算法. ...

  5. C++11学习笔记-----互斥量以及条件变量的使用

    在多线程环境中,当多个线程同时访问共享资源时,由于操作系统CPU调度的缘故,经常会出现一个线程执行到一半突然切换到另一个线程的情况.以多个线程同时对一个共享变量做加法运算为例,自增的汇编指令大致如下, ...

  6. FreeRTOS学习笔记

    FreeRTOS学习笔记 (这是我自己学习FreeRTOS整理的笔记,仅供参考) 第一部分:实现FreeRTOS内核 变量名: 定义变量时往往会把变量的类型当作前缀加在变量上 变量类型 前缀 char ...

  7. 1、野火freertos学习笔记

    野火freertos学习笔记 1.任务 1.1 栈 1.2 任务的切换 taskYIELD(); 1.3 临界段 2.空闲任务 3.任务优先级 4.任务延时的表现 5.时间片 5.1抢占式.协做式 6 ...

  8. freeRtos学习笔记 (7)信号量

    freeRtos学习笔记 freeRtos信号量 信号量种类 信号量分为四种:二值信号量,互斥信号量,计数信号量和递归互斥信号量,其中计数信号量用于管理系统多个共享资源,用计数值表示可用资源数目;二值 ...

  9. FreeRtos学习笔记(11)查找就绪任务中优先级最高任务原理刨析

    FreeRtos学习笔记(11)查找就绪任务中优先级最高任务原理刨析 怎么查找就绪任务中优先级最高的? tasks.c中声明了一个全局变量 uxTopReadyPriority,任务从其他状态进入就绪 ...

最新文章

  1. 在Simulink中创建库
  2. guava_使用Google Guava Cache进行本地缓存
  3. js怎么实现对html代码加密解密,javascript脚本加密解密及HTML转JS
  4. SQL 连接字符串的说明(转)
  5. 咋样查mysql的url_eclipse用jdbc连接mysql数据库时,url是填什么?怎样找出地址?
  6. python pyquery安装_win7下python安装pyquery
  7. 01-02 Linux常用命令-文件处理
  8. 微软MCITP系列课程(十)WSUS服务器搭建
  9. 图论 - 寻找fly真迹
  10. IPOP下的tcl脚本
  11. vs2010 sp1安装
  12. Qt数据库应用3-数据打印到pdf
  13. 支付宝芝麻信用分申请
  14. 解决UWP应用无法使用本地代理
  15. 一线互联网互联网架构师自述:GitHub标星10w+,2021最新Android笔经
  16. veu +Apipost下拉框选项绑定数据库
  17. Unity 2018升级2020后XR报错error CS0619: ‘XRDevice.isPresent‘ is obsolete
  18. 计算机网络序号是什么,Excel序号是什么 Excel序号详细介绍
  19. Excel:批量将某字符替换为“换行符”
  20. MT4自定义指标导入方法

热门文章

  1. dlsym 如何查看一个so里面的_如何查看并且使用android系统本身包含的so库?
  2. php 中间表统计,多对多中间表详解
  3. SpringCloud Consul Config 配置中心 (二)
  4. 解决appium-inspector连接后在Appium中报错:No route found for /sessions
  5. linux nohup后台执行管道操作
  6. python json转dict(dict转json)
  7. flink java生成流式数据
  8. java对csv格式的读写操作
  9. python filter函数 字符串_Python实现filter函数实现字符串切分
  10. mysql df_DF学Mysql(一)——数据库基本操作