FreeRTOS学习笔记(3、信号量、互斥量的使用)

2023-11-05

FreeRTOS学习笔记(3、信号量、互斥量的使用)

前言

这是第三弹,由于CSDN长度的限制,所以把FreeRTOS学习分为几部分来发,这是第三部分


主要包括信号量、互斥量使用

往期学习笔记链接

第一弹FreeRTOS学习笔记(1、FreeRTOS初识、任务的创建以及任务状态理论、调度算法等)
第二弹: FreeRTOS学习笔记(2、同步与互斥通信、队列、队列集的使用)
第三弹: FreeRTOS学习笔记(3、信号量、互斥量的使用)
第四弹: FreeRTOS学习笔记(4、事件组、任务通知)
第五弹: FreeRTOS学习笔记(5、定时器、中断管理、调试与优化)

学习工程

所有学习工程
oufen / FreeRTOS学习
都在我的Gitee工程当中,大家可以参考学习

信号量 semaphore

队列可以传送数据,队列可以传送不同的数据

有的时候只需要传递状态,并不需要传递具体的信息

这就是信号量,不去传送数据,而是传送状态,这样至起到了通知的作用,更加节省内存

信号量,不能传输数据,只有一个计数值,来表示资源的数量


信号起通知作用

量,表示资源的数量

左边是生产者,生产好一个商品后让计数值+1
右边是消费者,取出一个商品后计数值-1

如何创建信号量

  • 创建信号量
  • 生产者生产好后让计数值+1 give
  • 消费者取出后让计数值-1 take

计数:事件产生give信号量,计数值加1,处理事件,take信号量,计数值减1
资源管理:想要访问资源时,首先需要take信号量,计数值减1,用完资源后,give信号量,计数值加1

image.png

两种信号量的对比

  • 计数型信号量
  • 二进制信号量

计数型信号量,的取值范围为0-任意数

二进制信号量,的取值返回为0或者1 但是二进制信号量的初始值为0

除了取值不一样外,其他的操作都是完全一样的

信号量也相当于是一个队列

队列有一个结构体Queue,结构体中有一个指针,指向存放数据的一个buff

但是对于信号量,并不需要这个buffer,只需要这个结构体

对于信号量,核心是信号量的计数值
这个计数值保存在初始化信号量时传入的初始的计数值

image.png

创建完信号量后,就可以加减信号量的Value了
让信号量的计数值+1,并且取出东西

一开始Value为0,调用take函数,使信号量减1,没有数据,那么信号量就没办法-1,进入阻塞状态,还可以指定阻塞多长时间
在阻塞状态中,如果有另一个task往里面放数据,那么就会从阻塞状态中唤醒,进入Ready状态

  1. 对于give,信号量加1 解锁

对于计数型信号量,可以让这个值累加,但是不能超过创建时指定的最大值

对于二进制信号量,取值就只有0和1,如果值为1,再次调用give也不会成功
可以判断give函数的返回值,看累加是否成功

不管哪种信号量,只要没有超过创建时指定的最大值,都可以累加成功
image.png

  1. 对于take,信号量-1 上锁

如果信号量的值为0,就没办法take成功,不成功的话可以指定阻塞时间

  • 0 take不成功,返回err
  • portMax_Delay 一直阻塞,直到成功
  1. 有多个task执行take,当其他task执行give时,唤醒哪个任务?
  • 优先级最高的task 优先执行take
  • **优先级相同时,等待最久的task ** 优先执行take

image.png
pdTRUE,表示Take成功

小问题:
使用队列也可以实现同步,为什么还要使用信号量呢?

  • 使用队列可以传递数据,数据的保存需要空间
  • 使用信号量时不需要传递数据,更加节省空间
  • 使用信号量时不需要复制数据,效率更高

image.png

信号量的使用

使用信号量时,先创建,然后去添加资源,获得资源,使用句柄来表示一个信号量

需要定义这两个宏

#define configSUPPORT_DYNAMIC_ALLOCATION 1 /*信号量相关宏*/
#define configUSE_COUNTING_SEMAPHORES 1

image.png
image.png

1、创建信号量

初始值为0 信号量计数值 最大值为10
image.png

2、give

image.png
image.png

3、take

image.png
image.png

4、删除信号量

对于动态创建的信号量,如果不使用,不再需要时,可以删除他们以回收内存
image.png

使用计数型信号量实现同步功能

虽然实现了同步功能,但是对于数据的完整性,需要我们自己来做
image.png

使用二进制型信号量实现互斥功能

注意了二进制型信号量初始值为0
所以创建二进制信号量时需要,手动give一下,否则take时会一直卡在阻塞状态

task3和task4独占的使用串口

创建二进制信号量来实现互斥
image.png

image.png

task3和task4实现了串口的独占使用,即实现互斥功能
image.png

互斥量 mutex

互斥量是一个特殊的二进制信号量

**任务A访问这些全局变量、函数代码时,独占它,就是上个锁。这些全局变
量、函数代码必须被独占地使用,它们被称为临界资源 **

互斥量,就是用来保护临界资源,大家互斥的使用这些资源

image.png

二进制信号量也能实现互斥
image.png

当出现一种情况

TaskA获得信号量,计数值-1,此时二进制信号量为0
打印数据
此时TaskC运行另一个函数,give信号量,计数值+1,此时二进制信号量为1
此时TaskB从阻塞状态,进入Ready态
也能打印数据

此时串口被两个Task使用,就不是独占关系,不是互斥,对临界资源进行使用

本来应该是TaskA上锁(获得信号量,使信号量的计数值为0)
打印完数据后,应该由TaskA自己解锁
可是其他任务帮TaskA解锁,造成串口不是独占使用

要解决这样的问题,就应该是谁上锁,谁来解锁
二进制信号量并不能保证,谁上锁,谁解锁
虽然互斥量也不能保证

但是互斥量可以解决

  • 优先级反转
  • 解决递归上锁/解锁的问题

如何实现谁上锁,谁解锁

  • 上锁、解锁代码成对出现
  • 在临界代码中(想要某种资源被独占使用),不要解锁

问题:优先级反转

什么是优先级反转?
A/B/C的优先级分别是 1 2 3
A先运行,获得了锁,此时进入阻塞状态
B优先级比A高,抢占进入Running状态
由于A已经使用了锁,所以进入阻塞状态
C的优先级比B高,此时C运行,也想获得锁,因为A已经使用了锁,所以C进入阻塞状态
此时优先级高的Task优先执行,轮到B运行
在B运行过程中,一直没有放弃CPU资源,此时A不能执行

在这种情况下,C的优先级最高,A的优先级最低,结果优先级最高的C被B抢占了

优先级高的程序反而不能执行,这就是优先级反转
image.png

解决方法:优先级继承

解决优先级反转的方法就是使用优先级继承

什么是优先级继承?

在C获得锁Take,因为锁被A上锁了,所以进入阻塞状态,进入阻塞状态的同时会进行优先级继承
此时A的优先级变成了C的优先级,A继承了C的优先级
此时A的优先级变为了3,所以C阻塞后,A开始运行
A对锁进行解锁,unlock,释放互斥量,A的优先级又变成了原来的优先级1
然后轮到C来执行

这个过程中C的优先级并没有被B来反转,优先级继承解决了上述优先级反转的问题

优先级继承的好处在于提升优先级,如果C的优先级比A的还低,就没有继承的必要

问题:递归上锁造成死锁

image.png

这是自我死锁

TaskA运行,上锁后,信号量计数值为0,打印数据
进入xxxlib函数,再次上锁,因为信号量计数值为0,无法继续上锁,所以进入阻塞状态
进入阻塞状态,没有办法解锁,造成了死锁

image.png

解决方法:递归锁

递归锁是互斥量的另外一种形式

在上锁了之后,还可以二次上锁,但是二次上锁后要解锁,否则会进入阻塞状态
一次上锁对应一次解锁

此时B来上锁,就会进入阻塞状态
image.png

互斥量分为两种

  • 普通的互斥量
    • 具有优先级继承的功能
  • 递归锁
    • 除了具有优先级继承的功能外
    • 递归的功能

互斥量的基本使用

1、创建互斥量

二进制型信号量的初始值为0,所以创建时需要手动give释放一下,计数值+1,否则take时,计数值无法减1,将会发生阻塞

而互斥量的初始值为1,创建后不需要Give一次

image.png
创建互斥量时还需要配置宏
image.png
image.png

/*互斥量相关宏*/
#define configUSE_MUTEXES 1
2、获得互斥量 Take

image.png

3、释放互斥量 Give

image.png

image.png

使用优先级继承来实现优先级反转

二进制信号量优先级反转的过程分析

此时是二进制型信号量

image.png
下图就是优先级反转的例子
image.png

image.png

根据波形图对
优先级反转详细说明
image.png
image.png
image.png
image.png
image.png
image.png

互斥量使用优先级继承来解决优先级反转

image.png
image.png
image.png

互斥量和二进制信号量的区别和共同点

  1. 互斥量初始值为1

  2. 二进制信号量初始值为0

  3. Give/Take函数完全一样

  4. 互斥量具有优先级继承的功能

互斥量的递归锁

互斥量,本意是谁持有,谁释放

但是FreeRTOS没有实现这一点

A持有,B也可以释放

但是互斥量的递归锁实现了

谁持有,就有谁释放
递归上锁和解锁

一般的互斥量,并没有实现,谁持有,就由谁释放
image.png

递归锁实现

image.png

1、创建递归锁

image.png

递归锁实现,要首先配置相关宏
image.png

FreeRTOS为了减小程序的体积,使用某些功能时,首先需要配置

2、Give/Take

和信号量不同的是Give/Take的函数发生改变

同时递归锁能够实现谁上锁,谁解锁的功能

image.png
image.png

递归锁可以让task互斥使用串口

递归锁实现了谁持有,就由谁来释放

递归锁内部会记录持有者,对于持有递归锁的task,可以循环的使用上锁,开锁

image.png

image.png

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

FreeRTOS学习笔记(3、信号量、互斥量的使用) 的相关文章

  • 阿里巴巴大神发布的Java零基础笔记,实战教程多到手软,跪了

    前言 现值金九银十之际 是面试高峰季 很多学校开始校招 也是跳槽转行的最佳时机 根据数据显示 程序员是金九银十里最热门的行业 也是需求量最大的行业 但是程序员是个门槛低 但金字塔顶峰比较高的行业 意味着你的付出要比别人多才能拔尖 我们都知道
  • Python采集猎聘网站招聘数据内容,看看现在职位风向

    嗨喽 大家好呀 这里是爱看美女的茜茜呐 环境使用 Python 3 10 Pycharm 模块使用 第三方模块 需安装 requests gt pip install requests pandas gt pip install panda
  • 2020年认证杯SPSSPRO杯数学建模D题(第二阶段)让电脑桌面飞起来全过程文档及程序

    2020年认证杯SPSSPRO杯数学建模 D题 让电脑桌面飞起来 原题再现 对于一些必须每天使用电脑工作的白领来说 电脑桌面有着非常特殊的意义 通常一些频繁使用或者比较重要的图标会一直保留在桌面上 但是随着时间的推移 桌面上的图标会越来越多
  • MIT_线性代数笔记:复习二

    目录 第二单元主要内容 例题 第二单元主要内容 正交矩阵 Q 用矩阵形式描述正交性质 投影矩阵 P 最小二乘法 在方程无解时求 最优解 Gram Schmidt 正交化 从任意一组基得到标准正交基 策略是从向量 中减去投影到其它向量方向的分
  • 【计算机毕业设计】实验室预约管理

    身处网络时代 随着网络系统体系发展的不断成熟和完善 人们的生活也随之发生了很大的变化 人们在追求较高物质生活的同时 也在想着如何使自身的精神内涵得到提升 而读书就是人们获得精神享受非常重要的途径 为了满足人们随时随地只要有网络就可以看书的要
  • 小白也能学会的创建Git仓库实操

    2024软件测试面试刷题 这个小程序 永久刷题 靠它快速找到工作了 刷题APP的天花板 CSDN博客 文章浏览阅读2 2k次 点赞85次 收藏11次 你知不知道有这么一个软件测试面试的刷题小程序 里面包含了面试常问的软件测试基础题 web自
  • 白帽子如何快速挖到人生的第一个漏洞 | 购物站点挖掘商城漏洞

    本文针对人群 很多朋友们接触安全都是通过书籍 网上流传的PDF 亦或是通过论坛里的文章 但可能经过了这样一段时间的学习 了解了一些常见漏洞的原理之后 对于漏洞挖掘还不是很清楚 甚至不明白如何下手 可能你通过 sql labs 初步掌握了sq
  • 嵌入式开发--STM32G4系列片上FLASH的读写

    这个玩意吧 说起来很简单 就是几行代码的事 但楞是折腾了我大半天时间才搞定 原因后面说 先看代码吧 读操作 读操作很简单 以32位方式读取的时候是这样的 data IO uint32 t 0x0800F000 需要注意的是 当以32位方式读
  • C和指针课后答案

    提示 文章写完后 目录可以自动生成 如何生成可参考右边的帮助文档 文章目录 前言 一 pandas是什么 二 使用步骤 1 引入库 2 读入数据 总结 前言 第八章课后答案 提示 以下是本篇文章正文内容 下面案例可供参考
  • c语言学生管理系统

    创建结构体里面包含学生的各种信息 struct xs int xh char xm 20 int gs yy wl double pj struct xs next 创建菜单 void menu printf n n printf 学生管理
  • msyql 异常,别干着急,70%的问题都在这里!

    2024软件测试面试刷题 这个小程序 永久刷题 靠它快速找到工作了 刷题APP的天花板 CSDN博客 文章浏览阅读2 3k次 点赞85次 收藏11次 你知不知道有这么一个软件测试面试的刷题小程序 里面包含了面试常问的软件测试基础题 web自
  • 用栈实现队列(OJ中报错的处理)

    用栈实现队列 ERROR AddressSanitizer myQueueFree函数中栈的释放处现了问题 没有调用StackDestory而是直接free了 这个是栈初始化时 capacity与malloc申请的空间大小没有匹配 请你仅使
  • 新画图不好用?『 图层困扰?』『 剪切板拷贝失败?』旧版画图软件yyds

    樊梓慕 个人主页 个人专栏 C语言
  • 为什么我强烈推荐大学生打CTF!

    前言 写这个文章是因为我很多粉丝都是学生 经常有人问 感觉大一第一个学期忙忙碌碌的过去了 啥都会一点 但是自己很难系统的学习到整个知识体系 很迷茫 想知道要如何高效学习 这篇文章我主要就围绕两点 减少那些罗里吧嗦的废话 直接上干货 CTF如
  • systick定时器

    systick定时器 文章目录 前言 一 前期疑惑 二 解答 1 关于systick是阻塞的吗 2 非阻塞 三 软件编写 总结 前言 这边记录systick相关知识点 一 前期疑惑 在学习systick志气啊 其实对于systick还是一脸
  • 【js学习之路】遍历数组api之 `filter `和 `map`的区别

    一 前言 数组是我们在项目中经常使用的数据类型 今天我们主要简述作用于遍历数组的api filter 和 map 的区别 二 filter和map的共同点 首先 我们主要阐述一下 filter 和 map 的共同点 api的参数都是回调函数
  • PWM DMA 到整个 GPIO

    我有一个 STM32F4 我想对一个已与掩码进行 或 运算的 GPIO 端口进行 PWM 处理 所以 也许我们想要 PWM0b00100010一段时间为 200khz 但随后 10khz 后 我们现在想要 PWM0b00010001 然后
  • 在 Contiki 程序中使用 malloc

    考虑以下 Contiki 程序 include
  • 使用 STM32 USB 设备库将闪存作为大容量存储设备

    我的板上有这个闪存IC 它连接到我的STM32F04 ARM处理器 处理器的USB端口可供用户使用 我希望我的闪存在通过 USB 连接到 PC 时被检测为存储设备 作为第一步 我在程序中将 USB 类定义为 MSC 效果很好 因为当我将主板
  • 小型 ARM 微控制器的 RTOS 内核之间的可量化差异 [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 有许多不同的 RTOS 可用于微控制器 我专门寻找支持 ARM Cortex M 处理器的 RTOS 另外 我对闭源解决方案不感兴趣 试图从网站

随机推荐

  • 多文件编辑作业(2023.1.9)

    第一题 main c include head h int main int argc const char argv char str 10 abcdefg MyStrRev str char a hello StrRevRec a st
  • qt 在ui界面添加控件后在cpp文件中无法调用?

    问题 qt 在ui界面添加控件后在cpp文件中无法调用 解决方法 在build选项中选择 重新build项目 再次在cpp中调用添加的控件发现可以调用了 还有一种情况导致添加控件后无法调用 就是没有导入ui xxx h文件 xxx是ui界面
  • Python图像处理-4.pil调整图片尺寸和旋转角度

    from PIL import Image import matplotlib pyplot as plt pil im1 Image open pic1 png plt figure girlfriend1 plt imshow pil
  • 魔搭开源FaceChain个人写真项目,大幅提升写真多样性,登顶github趋势榜首!

    一 上周数据概览 一周时间获取超过3K star 连续在github trending榜单蝉联top 开发者们纷纷标记star GitHub modelscope facechain FaceChain is a deep learning
  • zlib库VS2017编译步骤

    点击这里下载zlib1 2 11源码 http zlib net zlib1211 zip 下载源码库 从上面给出的源码路径下载zlib源码库 如果不想自己编译 可以使用上面给出的二进制包直接使用 无视本文 编译步骤 编译方法一 解压源码文
  • MyBatis-plus 动态条件构造器总结

    MyBatis plus 动态条件构造器类结构图 MyBatis Plus条件构造器QueryWrapper对应常用SQL语法说明 函数 说明 SQL语法 eq 等于 ne 不等于 lt gt gt 大于 gt lt 小于 lt ge 大于
  • STM32单片机通过ESP8266WiFi模块与Android APP实现数据传输(一)---下位机硬件配置

    事务的难度远远低于对事物的恐惧 STM32F407单片机通过ESP8266 WiFi模块与Android 手机APP连接实现数据的相互传输 在单片机上通过LCD显示屏实时显示连接的状态以及互相传输的数据 先看效果图 STM32单片机 And
  • simulink教程(自动控制原理)

    1 启动simulink 命令行输入simulink或者 会弹出 2 点击blank model 出现新窗口 新建或者打开模型文件 There are two major classes of items in Simulink block
  • GLES3.0中文API-glDrawRangeElements

    名称 glDrawRangeElements 从数组数据渲染基元 C规范 void glDrawRangeElements GLenum mode GLuint start GLuint end GLsizei count GLenum t
  • Open mv识别三角形的办法

    文章目录 前言 带着问题来看 一 函数 二 使用方法 1 find line segments 2 img find template 三 摄像情况及终端结果 1 find line segments 2 img find template
  • 初始C语言——利用Ascll码进行字母大小写转换

    打开Ascll码表 你会发现大写字母和小写字母之间存在这样的关系 图片来自 https img blog csdnimg cn 54404234b42348d6a33bc1c4d5ab24e5 png 小写字母的值始终比大写字母多32 de
  • Node.js

    Node js Node js基础 概念 简单的说 Node js 就是运行在服务端的 JavaScript Node js 是一个基于Chrome JavaScript 运行时建立的一个平台 Node js是一个事件驱动I O服务端Jav
  • (五)决策树

    一 决策树 决策树是监督学习算法 下面为一些样本 本质上是一种特征去结果的相关度 比如你的信贷情况与能否还贷的相关度肯定高 而你有没有结婚的相关度肯定低 二 信息增益 三 ID3算法
  • php 未支付取消订单,【php】用户提交订单,30分钟后没付款取消订单功能分析

    我先在要做这样的功能 用户在创建订单后 订单表中记入的是未付款状态 如果用户在30分钟后 还未付款 然后就把该订单给取消 关于用户创建订单 30分钟后还没付款 取消该订单的逻辑是怎么实现的 我自己的想了两个方案 1 客户端记入这个订单 如果
  • MindNode 5 for Mac(思维导图软件)中文版

    绘制流程图 思维导图 规划图 信息图等自然少不了这款MindNode 5 for Mac 作为优质的思维导图软件 mindnode5 mac破解版的功能很全面 添加文字 链接 图片 扩展注释等非常便捷 而且mindnode 5 破解版会智能
  • Rocketmq原理&最佳实践

    一 MQ背景 选型 消息队列作为高并发系统的核心组件之一 能够帮助业务系统解构提升开发效率和系统稳定性 主要具有以下优势 削峰填谷 主要解决瞬时写压力大于应用服务能力导致消息丢失 系统奔溃等问题 系统解耦 解决不同重要程度 不同能力级别系统
  • Python开发篇——基于React-Dropzone开发上传组件

    这次我要讲述的是在React Flask框架上开发上传组件的技巧 我目前主要以React开发前端 在这个过程中认识到了许多有趣的前端UI框架 React Bootstrap Ant Design Material UI Bulma等 而比较
  • Linux操作系统知识点总结

    1 什么是Linux系统 Linux 全称GNU Linux 是一种免费使用和自由传播的类UNIX操作系统 其内核由林纳斯 本纳第克特 托瓦兹 Linus Benedict Torvalds 于1991年10月5日首次发布 它主要受到Min
  • Qt 实现自定义Ui控件例子,以自定义的Slider为例(QWidget)

    说明 Qt可以比较方便地实现自定义控件在Qt Creator中使用 网上也有很多大神的控件可以使用 但是如果想要自己简单定制也可以按照这个流程 本文的要点 1 如何实现一个自定义控件 本文使用的方法有两个步骤 先在一个普通项目中实现使用 新
  • FreeRTOS学习笔记(3、信号量、互斥量的使用)

    FreeRTOS学习笔记 3 信号量 互斥量的使用 前言 往期学习笔记链接 学习工程 信号量 semaphore 两种信号量的对比 信号量的使用 1 创建信号量 2 give 3 take 4 删除信号量 使用计数型信号量实现同步功能 使用