FreeRTOS笔记(六)互斥量mutex

2023-05-16

概念

互斥量是二进制信号量的一个变种,开启互斥量需要在头文件FreeRTOSConfig.h设置configUSE_MUTEXES 为1。互斥量和信号量的主要区别如下

  • 互斥量用于保护资源时必须要被返还

  • 信号量用于数据同步时不需要返还

必须被独占地使用的全局变量、函数代码,它们被称为临界资源。

互斥量也被称为互斥锁,使用过程如下:

  1. 互斥量初始值为 1

  1. 任务 A 想访问临界资源,先获得并占有互斥量,然后开始访问

  1. 任务 B 也想访问临界资源,也要先获得互斥量:被别人占有了,于是阻塞

  1. 任务 A 使用完毕,释放互斥量;任务 B 被唤醒、得到并占有互斥量,然后开始访问临界资源

  1. 任务 B 使用完毕,释放互斥量

互斥型信号量必须是同一个任务申请,同一个任务释放,其他任务释放无效。同一个任务可以递归申请。

二进制信号量,一个任务申请成功后,可以由另一个任务释放。

二进制信号量实现任务互斥:
打印机资源只有一个,abc三个任务共享,当a取得使用权后,为了防止其他任务错误地释放了信号量(),必须将打印机房的门关起来(进入临界段),用完后,释放信号量,再把门打开(出临界段),其他任务再进去打印。(而互斥型信号量由于必须由取得信号量的那个任务释放,故不会出现其他任务错误地释放了信号量的情况出现,故不需要有临界段。互斥型信号量是二进制信号量的子集。)
二进制信号量实现任务同步:
a任务一直等待信号量,b任务定时释放信号量,完成同步功能

互斥量操作的相关函数

要想使用互斥量,需要在配置文件 FreeRTOSConfig.h 中定义:

##define configUSE_MUTEXES 1

创建互斥量

动态创建一个互斥量:

SemaphoreHandle_txSemaphoreCreateMutex( void )

xSemaphoreCreateMutex()函数用于创建互斥量

静态创建互斥量:

SemaphoreHandle_txSemaphoreCreateMutexStatic( StaticSemaphore_t*pxMutexBuffer );

创建一个互斥量,返回它的句柄。
此函数无需动态分配内存,所以需要先有一个StaticSemaphore_t 结构体,并传入它的指针
返回值: 返回句柄,非 NULL 表示成功

要注意的是,互斥量不能在 ISR 中使用。

其他函数

/*

* xSemaphore: 信号量句柄,你要删除哪个信号量, 互斥量也是一种信号量

*/

voidvSemaphoreDelete( SemaphoreHandle_txSemaphore );

/* 释放 */

BaseType_txSemaphoreGive( SemaphoreHandle_txSemaphore );

/* 释放(ISR 版本) */

BaseType_txSemaphoreGiveFromISR(

SemaphoreHandle_txSemaphore,BaseType_t*pxHigherPriorityTaskWoken

);

/* 获得 */

BaseType_txSemaphoreTake(

SemaphoreHandle_txSemaphore,

TickType_txTicksToWait

);

/* 获得(ISR 版本) */

xSemaphoreGiveFromISR(

SemaphoreHandle_txSemaphore,

BaseType_t*pxHigherPriorityTaskWoken

);

互斥量的应用伪代码

使用互斥量时有如下特点:
  • 刚创建的互斥量可以被成功"take"

  • "take"互斥量成功的任务,被称为"holder",只能由它"give"互斥量;别的任务"give"不成功

  • 在 ISR 中不能使用互斥量

  • 本程序创建 2 个发送任务:故意发送大量的字符。 可以做 2 个实验:

  • 使用互斥量:可以看到任务 1、任务 2 打印的字符串没有混杂在一起

  • 不使用互斥量:任务 1、任务 2 打印的字符串混杂在一起

首先申明个互斥量的全局变量

SemaphoreHandle_t xMutex;

然后在main函数中创建互斥量

intmain(void)

{

...

xMutex=xSemaphoreCreateMutex();

...

}

voidFunction_Resource(voidconst*argument)

{

//要保护的资源函数

...

xSemaphoreTake( xMutex, portMAX_DELAY );

{

//对资源的处理

...

}

xSemaphoreGive( xMutex );

...

}

在上段代码中,如果有多个任务要调用资源函数的话,通过资源函数内部的互斥量机制可以保护资源不被其他任务打断。关于互斥量如何解决优先级倒置的问题,FreeRTOS为互斥量赋予了优先级继承(priority inheritance)的特性。优先级继承会暂时提高获得互斥量的任务的优先级,使得含有互斥量的任务的优先级和想要获取互斥量的任务中的最高优先级一样。互斥量无法彻底避免优先级倒置的问题,但能显著降低优先级倒置发生的概率。

死锁

假设有 2 个互斥量 M1、 M2, 2 个任务 A、 B:

  1. A 获得了互斥量 M1

  1. B 获得了互斥量 M2

  1. A 还要获得互斥量 M2 才能运行,结果 A 阻塞

  1. B 还要获得互斥量 M1 才能运行,结果 B 阻塞

  1. A、 B 都阻塞,再无法释放它们持有的互斥量

  1. 死锁发生!

自我死锁
  1. 任务 A 获得了互斥锁 M

  1. 它调用一个库函数

  1. 库函数要去获取同一个互斥锁 M,于是它阻塞:任务 A 休眠,等待任务 A来释放互斥锁!

  1. 死锁发生!

递归锁
  • 任务 A 获得递归锁 M 后,它还可以多次去获得这个锁

  • "take"了 N 次,要"give"N 次,这个锁才会被释放

递归锁

一般互斥量

创建

xSemaphoreCreateRecursiveMutex

xSemaphoreCreateMutex

获得

xSemaphoreTakeRecursive

xSemaphoreTake

释放

xSemaphoreGiveRecursive

xSemaphoreGive

/* 创建一个递归锁,返回它的句柄。

* 此函数内部会分配互斥量结构体

* 返回值: 返回句柄,非 NULL 表示成功

*/

SemaphoreHandle_txSemaphoreCreateRecursiveMutex( void );

/* 释放 */

BaseType_txSemaphoreGiveRecursive( SemaphoreHandle_txSemaphore );

/* 获得 */

BaseType_txSemaphoreTakeRecursive(

SemaphoreHandle_txSemaphore,

TickType_txTicksToWait

);

资源管理

资源管理(Resource Management)顾名思义,就是对资源的管理。资源在FreeRTOS中可以表现为一个负责保存数据的全局变量,一个队列上的数据等需要在任务之间共享的数据或者对UART串口的操作资源等。

资源管理主要包括两个方面内容--数据的同步机制资源的保护机制

资源的保护与互斥量

资源的保护是指,如何保护资源不被多个任务同时操作。如果一个保存数据的全局变量在被一个任务操作的过程中,又被多个更高优先级的任务抢占并处理,那么最后这个支离破碎的数据将会毫无意义,破坏了数据的独立完整性;如果一个任务在使用uart串口发送数据的时候,又被多个更高优先级的任务抢占串口资源并发送数据,那么最后串口发送的数据将只是一堆乱码毫无意义,会导致系统的不稳定。

信号量用于资源保护

在上图中,有个低优先级的任务(LP)和高优先级的任务(HP),两个任务都可以对一个资源进行操作。为了对资源进行保护采用了信号量的机制。LP首先获得信号量可以对资源进行操作,在时刻1,HP因为优先级高在内核调度中抢占了LP,在时刻2,HP想获得信号量但失败因此进入了阻塞状态。之后LP可以继续对资源操作,在时刻3执行完毕后归还了信号量。在时刻4,HP因为优先级高在内核调度中抢占了LP并获取了信号量可以对资源可以操作。

优先级倒置

在上面这个示例中,不同优先级的任务采用信号量机制可以独立地使用资源并不会被打断,因此保护了资源。但采用信号量保护资源的话会有个弊端,有时会产生一种现象叫做优先级倒置(Priority inversion )。下图将介绍这个现象。

这个示例和上图示例基本相同,就是多了一个优先级介于LP和HP之间的任务(MP),问题发生在时刻3。此时低优先级的任务获得了信号量和对资源的操作权,但被优先级更高的MP抢占了并执行。最高优先级的任务HP等待低优先级任务LP返还信号量,而低优先级因为被中等优先级的任务MD抢占无法返回信号量。从外部的视角看,此时中等优先级的任务MD相当于抢占了高优先级的任务HP,而高优先级的任务HP表现起来却又像是有最低的优先级。这种不正常的现象就被称为优先级倒置。优先级倒置是采用信号量保护资源可能会产生的负面效果。

关键区

关键区(Critical Section)是资源保护的另一种方法。在FreeRTOS有两个宏定义,分别是taskENTER_CRITICAL()taskEXIT_CRITICAL()

代码如下

taskENTER_CRITICAL();

...

taskEXIT_CRITICAL();

taskENTER_CRITICAL()宏定义会关闭所有中断包括内核切换所在的中断,taskEXIT_CRITICAL()宏定义会再次打开中断。所以处于宏定义之间的代码可以被独占地执行,这是保护资源的一种比较暴力的方式。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

FreeRTOS笔记(六)互斥量mutex 的相关文章

随机推荐

  • 嵌入式linux项目之智能仓储(基于正点原子IMX6ULL开发板)

    基于正点原子的IMX6ULL开发板的智能仓储项目 提示 xff1a 该项目根据华清远见智能仓储项目改版 xff0c 将他的A9开发板换成了自己的IMX6ULL开发板 同时等我将该项目整个流程完成之后 xff0c 会为大家附上适配正点原子li
  • STM32电路知识学习

    STM32最小系统板电路知识学习 单片机最小系统是指用最少的电路组成单片机可以工作的系统 xff0c 通常最小系统包含 xff1a 电源电路 时钟电路 复位电路 调试 下载电路 xff0c 对于STM32还需要启动选择电路 总之 xff0c
  • ubuntu18.04运行vins-fusion跑通自己的数据集

    博主是双目加imu 命令 xff1a xff08 一定要记得改成自己的路径哦 xff09 cd catkin ws source devel setup bash roslaunch vins vins rviz launch source
  • 17.C语言 常见面试题

    嵌入式工程师必备0x10到题目 宏定义 1 用预处理指令 define声明一个常数 xff0c 用于表明1年中有多少秒 define 宏名 宏体 宏名 xff1a 大写字母表示 define SECOND OF YEAR 365 24 36
  • 自动控制原理第一章

    开环控制系统 xff1a 输入量与输出量没有反向联系 被控量 xff08 输出信号 xff09 xff0c 系统在特定输入下的输出称系统对该输入的响应 控制量 xff08 输入信号 xff09 给定值 扰动 xff1a 破坏控制量与被控量正
  • 利用Mavros控制无人机

    准备 xff1a 1 ubuntu18 04 2 Qgc 3 Mavros 4 ROS 5 PX4 Mavros安装 xff1a 参考安装链接 xff1a Ubuntu18 04安装px4 43 mavros xff08 解决mavros报
  • 5分钟搭建MySQL监控平台(mysql-exporter+Prometheus+Grafana)

    一 工具介绍 Prometheus 普罗米修斯可以简单理解为一个监控工具 xff0c 以时间为单位展示指定数据维度的变化 趋势 span style color fe2c24 strong mysqld exporter strong sp
  • Prometheus环境搭建

    实验环境 xff1a 准备三台虚拟机 xff0c 本文用Centos7为例 xff1b 我这里所使用的的虚拟机地址分别为 xff1a 主机名 xff1a IP prometheus weme 192 168 10 63 agent weme
  • 无人机飞控系统硬件设计

    目录 一 飞行控制系统简介 1 飞控系统功能分析 2 飞控系统基本原理 3 飞控系统的组成部分 3 1 地面部分 3 2 中央处理器 3 3 传感器模块 3 4 传输定位模块 二 飞控系统硬件平台设计 一 飞行控制系统简介 1 飞控系统功能
  • Ubuntu20.04中怎么更换源都不行install或者update始终报错,解决方案

    更换源后安装或者更新依旧报错 xff0c 试试下面两种方法 xff0c 亲测可行 方法一 xff1a 静态ip改成动态ip 如果ip是静态改成动态ip后 xff0c 重新在试试apt update 1 vi etc netplan 00 i
  • AlphaGo 引发的中国象棋之路

    笔者是一位多年的象棋爱好者 xff0c 早在2005 xff0c 中国象棋有款软件奇兵1 04 xff0c 当时打败特级大师于幼华 xff0c 又打败了柳大华 xff0c 后期软件和计算机硬件的发展 xff0c 象棋软件又有了质的飞越 xf
  • linux驱动IO模型

    1 非阻塞 当应用层读取驱动中的数据时 xff0c 无论数据是否准备号 xff0c 都需要立即返回 open 34 dev mycdev 34 O RDWR O NOBLOCK 非阻塞方式打开 默认打开方式为阻塞方式打开 O NOBLIOC
  • ROS学习(一)工作空间,功能包,节点

    本文主要介绍建立一个功能包 xff0c 一个publisher结点 xff0c 实现话题的发布 一工作空间 1创建所需的文件夹 mkdir ros cd ros mkdir src 2工作空间的初始化 cd src catkin init
  • NVIDIA Jetson Xavier NX搭建pytorch gpu环境(超详细)

    NVIDIA Jetson Xavier NX开发套件在搭建tensorflow gpu环境时可以使用指令直接安装或者官网下载whl文件安装 作者在安装pytorch环境时总是安装不上gpu版本 报错 AssertionError Torc
  • uCOS-iii学习笔记(11)——任务信号量和任务消息队列

    理解 xff1a 任务信号量 任务消息队列是跟随任务创建而来的 xff0c 不需要额外创建 xff0c 并且他和多值信号量 消息队列有一些不同 xff0c 多值信号量他们是建立于1对多得关系 xff0c 而我们的任务信号量还有任务消息队列是
  • C语言当中什么情况下形参可以改变实参详细实例及解释

    在 C 语言中 xff0c 形参可以改变实参的值的情况与 C 43 43 类似 xff0c 也有传递指针和传递引用两种方式 传递指针 当我们传递一个指针作为函数的形参时 xff0c 函数内部同样可以通过这个指针来改变指向的实参的值 这是因为
  • git仓库与vscode关联

    git仓库与vscode关联 git安装完后 xff0c 会提示输入用户信息 a 设置用户名 xff1a git config global user name 39 你再github上注册的用户名 39 b 设置用户邮箱 xff1a gi
  • python修改全局变量

    span class token comment 全局变量 span num span class token operator 61 span span class token number 10 span span class toke
  • python函数不能修改全局变量

    span class token comment 全局变量 span num span class token operator 61 span span class token number 10 span span class toke
  • FreeRTOS笔记(六)互斥量mutex

    概念 互斥量是二进制信号量的一个变种 xff0c 开启互斥量需要在头文件FreeRTOSConfig h 设置configUSE MUTEXES 为1 互斥量和信号量的主要区别如下 互斥量用于保护资源时必须要被返还 信号量用于数据同步时不需