STM32FreeRTOS信号量(STM32cube高效开发)

一、信号量

(一)信号量概括

信号量是操作系统中重要的一部分,信号量是一种解决同步问题的机制,可以实现对共享资源的有序访问
在这里插入图片描述

FreeRTOS 提供了多种信号量,按信号量的功能可分为二值信号量、计数型信号量、互斥信号量和递归互斥信号量,不同类型的信号量有其不同的应用场景。

在这里插入图片描述
信号量(Semaphore)和互斥量(Mutex)都基于消息队列的基本数据结构,但是信号量和互斥量又有一些区别。
信号量没有优先级继承机制,使用二值信号量时容易出现优先级翻转问题,而二值信号量可以减缓优先级翻转问题。二值信号量适用于进程间同步,计数信号量适用于多个共享资源的访问控制,互斥量适用于对一个资源的互斥访问控制。

信号量与队列区别:
在这里插入图片描述

(二)二值信号量

1、二值信号量概述

二值信号量的本质是一个队列长度为 1 的队列 ,该队列就只有空和满两种情况。
二值信号量通常用于互斥访问或任务同步, 与互斥信号量比较类似,但是二值信号量有可能会导致优先级翻转的问题 ,所以二值信号量更适合用于同步
在这里插入图片描述
在这里插入图片描述

2、二值信号量使用

二值信号量(Binary Semaphore)就是只有一个项的队列。
二值信号量就像是一个标志,适合用于进程间同步的通信
在这里插入图片描述

(1)上图有两个进程,一个负责释放二值信号量,另外一个负责获取。ADC中断ISR读取ADC转换结果后写入数据缓冲区,数据处理任务负责读取缓冲区数据并进行处理。

(2)数据缓冲区是两个进程间同步访问的对象。
假设数据缓冲区只存储一次的转换结果数据,ADC中断ISR读取ADC转换结果后写入到缓冲区中,并且释放二值信号量,此时二值信号量有效,表示缓冲区有了新的数据(理解为自定义的标志变量,查询标志变量被置1表明有数据了可以下一步处理

(3)数据处理任务总是获取(Take)二值信号量。
有效后(理解为裸机开发中标志变量置位),任务立刻进入就绪状态参与任务调度,就可以读取缓冲区的数据并进行处理。无效时(理解为裸机开发中,数据处理完毕,清空标志位),任务在阻塞状态等待;

使用二值信号量的过程:创建二值信号量 -> 释放二值信号量-> 获取二值信号量

(三)计数信号量

计数型信号量与二值信号量类似, 二值信号量相当于队列长度为 1 的队列,因此二值信号量只能容纳一个资源,这也是为什么命名为二值信号量,而计数型信号量相当于队列长度大于0 的队列,因此计数型信号量能够容纳多个资源,这是在计数型信号量被创建的时候确定的。
在这里插入图片描述

1、事件计数:

每次事件发生后,在事件处理函数中释放计数型信号量(计数型信号量的
资源数加 1),其他等待事件发生的任务获取计数型信号量(计数型信号量的资源数减 1),这么一来等待事件发生的任务就可以在成功获取到计数型信号量之后执行相应的操作。

2、资源管理:

在这种场合下,计数型信号量的资源数代表着共享资源的可用数量,例如前面举例中停车场中的空车位。一个任务想要访问共享资源,就必须先获取这个共享资源的计数型信号量,之后在成功获取了计数型信号量之后,才可以对这个共享资源进行访问操作,当然,在使用完共享资源后也要释放这个共享资源的计数型信号量。在这种场合下,计数型信号量的资源数一般在创建时设置为受其管理的共享资源的最大可用数量。

在这里插入图片描述
(1)一个计数型信号量被创建时设置了初值4,这个值只是个计数值。
(2)有1个客人进店时就是获取(Take)信号量,计数信号量的值减1。当计数信号量的值变为0时,再有客人要进店时就得等待。
(3)如果有1个客人用餐结束离开了就是释放(Give)信号量,计数信号量的值加1,表示可用资源数量增加了1个。

(三)互斥量

1、互斥量概述

使用二值信号量时可能会出现优先级翻转的问题。互斥量引入了优先级继承机制,可以减缓优先级翻转问题。
互斥信号量其实就是一个拥有优先级继承的二值信号量,在同步的应用中(任务与任务或中断与任务之间的同步)二值信号量最适合。互斥信号量适合用于那些需要互斥访问的应用中
在这里插入图片描述
在互斥访问中互斥信号量相当于一把钥匙, 当任务想要访问共享资源的时候就必须先获得这把钥匙,当访问完共享资源以后就必须归还这把钥匙,这样其他的任务就可以拿着这把钥匙去访问资源。
在这里插入图片描述
(1)两个任务互斥性地访问串口,即在任务A访问串口时,其他任务不能访问串口。
(2)互斥量相当于管理串口的一把钥匙。一个任务可以获取(Take)互斥量,获得互斥量后将独占对串口的访问,访问完后要释放(Give)互斥量。
(3)一个任务获得互斥量后,对资源进行访问时,其他想要获取互斥量的进程只能等待。

2、二值信号量出现的优先级翻转问题

在这里插入图片描述
二值信号量也可以用于互斥型资源访问控制,但是容易出现
优先级翻转(Priority Inversion)问题

例如:
高优先级任务被低优先级任务阻塞,导致高优先级任务迟迟得不到调度。但其他中等优先级的任务却能抢到CPU资源。从现象上看,就像是中优先级的任务比高优先级任务具有更高的优先权(即优先级翻转)
在这里插入图片描述
已知:
任务L、任务M、任务H任务优先级依次是低中高,任务L和任务H需要获取信号量才能运行,任务M不需要获取信号量。
任务运行过程:
(1)刚开始低优先级任务获取信号量后,任务L处于运行中,高优先级任务H随后处于就绪状态,出现了比运行任务L优先级更高的任务,应该抢断低优先级任务的cpu占有权进入运行态,但是高优先级任务只有获取到信号量才能进入运行态(任务L占有信号量并没有释放),由于没有有效的信号量,所以高优先任务H无奈只能进入阻塞态等待信号量的释放,此时处于运行中的还是低优先级任务。
(2)一段时间以后,中优先级任务M处于就绪态,中优先级任务显然优先级高于运行中的低优先级任务L,由于不需要获取信号量即可运行,所以此时中优先级任务M打断低优先级任务L的运行,中优先级任务得到了cpu的使用权限进入了运行态。
(3)当中优先级任务M运行完毕之后,由于任务H无法获取信号量,迫不得已运行权限还是给到了任务L,等任务L运行完毕释放信号量后此时信号量变为有效,高优先任务H获取到信号量才得以运行。

总之:
从上面优先级翻转的示例中,可以看出,任务 H 为最高优先级的任务,因此任务 H 执行的操作需要有较高的实时性,但是由于优先级翻转的问题,导致了任务 H 需要等到任务 L 释放信号量才能够运行,并且,任务 L 还会被其他介于任务 H 与任务 L 任务优先级之间的任务 M 抢占,因此任务 H 还需等待任务 M 运行完毕,这显然不符合任务 H 需要的高实时性要求。

黑色表示任务L运行的时间段,红色表示任务H运行,蓝色表示任务M运行时间
在这里插入图片描述

  • 低优先级任务TaskLP在t1时刻开始处于运行状态,并且获取了一个二值信号量semp。

  • 在时刻t2,高优先级任务TaskHP进入运行状态,它申请二值 信号量semp,但是二值信号量被任务TaskLP占用,所以TaskHP在时刻t3进入阻塞等待状态,TaskLP进入运行状态

  • 在时刻t4,中等优先级任务TaskMP抢占了TaskLP的CPU使用权,TaskMP不使用二值信号量,所以它一直运行到时刻t5才进入阻塞状态。

  • 从t5时刻开始TaskLP又进入运行状态,直到t6时刻释放二值信号量semp,TaskHP才能进入运行状态。

在这里插入图片描述
高优先级的任务TaskHP需要等待低优先级的任务TaskLP释放二值信号量之后才可以运行,这也是期望的运行效果。但是在t4时刻,虽然任务TaskMP的优先级比TaskHP低,
但是它先于TaskHP抢占了CPU的使用权,这破坏了基于优先级抢占式执行的原则,对系统的实时性是有不利影响的。

3、互斥信号量优先级继承改善优先级翻转问题

当一个互斥信号量正在被一个低优先级的任务持有时, 如果此时有个高优先级的任务也尝试获取这个互斥信号量,那么这个高优先级的任务就会被阻塞。不过这个高优先级的任务会将低优先级任务的优先级提升到与自己相同的优先级。
在这里插入图片描述

互斥信号量下任务的运行过程
在这里插入图片描述

  • t1时刻:TaskLP处于运行状态,并且获得了一个互斥量mutex
  • t2时刻:TaskHP进入运行状态
  • t3时刻: TaskHP申请互斥量mutex,但是互斥量被TaskLP占用,TaskHP进入阻塞等待状态,TaskLP进入运行状态。但是在t3时刻,RTOS将TaskLP的优先级临时提高到与TaskHP相同的级别,这就是优先级继承。
  • t4时刻,TaskMP进入就绪状态,但是因为TaskLP的临时优先级高于TaskMP,所以TaskMP无法获得CPU的使用权
  • t5时刻:TaskLP释放互斥量,任务TaskHP立刻抢占CPU的使用权,并恢复TaskLP原来的优先级。
  • t6时刻:TaskHP进入阻塞状态后,TaskMP才进入运行状态。

二、信号量操作函数

信号量和互斥量的主要操作是释放和获取

(一)二值信号量

在这里插入图片描述
1、xSemaphoreCreateBinary() 创建信号量

二值信号量被创建后是无效的,相当于值为0。释放二值信号量就是使其有效,相当于使其变为1。(在创建二值信号量完毕,使用之前需要手动释放一次信号量让信号量变为有效)

关于二值信号量在创建后是否需要先释放一次,取决于使用场景和期望的行为:

  • 不先释放的情况:
    如果希望在信号量创建后立即表示资源是不可用的(例如,你可能希望在初始化资源或进行某些设置之后再允许其他线程访问),则不需要在创建后先释放信号量。
  • 先释放的情况:
    如果希望在信号量创建后立即表示资源是可用的,那么需要在创建后先释放一次信号量。
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )#define xSemaphoreCreateBinary() xQueueGenericCreate( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, queueQUEUE_TYPE_BINARY_SEMAPHORE )
#endif
//无参数、返回值是二值信号量句柄

官方例程:
(1)创建一个变量
(2)创建二值信号量将返回值赋值给创建的变量
(3)判断返回值是否为空,如果不为空表明创建成功
在这里插入图片描述
2、xSemaphoreGive()释放二值信号量
在释放信号量之前,需要先对要释放的信号量进行判断,判断信号量是否存在,存在的情况下才去执行相关的操作。

#define xSemaphoreGive( xSemaphore )		xQueueGenericSend( ( QueueHandle_t ) ( xSemaphore ), NULL, semGIVE_BLOCK_TIME, queueSEND_TO_BACK )参数1:是要释放的信号量句柄
返回值:pdTRUE表明释放成功

3、xSemaphoreTake()获取二值信号量

#define xSemaphoreTake( xSemaphore, xBlockTime )		xQueueSemaphoreTake( ( xSemaphore ), ( xBlockTime ) )
参数1:信号量句柄
参数2:阻塞时间
返回值:pdTRUE表明获取信号量成功

(二)计数信号量

使用计数型信号量的过程:创建计数型信号量 ->释放信号量 -> 获取信号量

在这里插入图片描述

1、创建计数信号量

#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )#define xSemaphoreCreateCounting( uxMaxCount, uxInitialCount ) xQueueCreateCountingSemaphore( ( uxMaxCount ), ( uxInitialCount ) )
#endif
参数1:计数信号量最大值
参数2:创建计数信号量时的初始值(计数用就设为0,有效资源个数就设为最大值)
返回值:计数信号量的句柄(NULL表示创建失败)

2、释放获取信号量同二值信号量

3、获取计数信号量当前计数值

#define uxSemaphoreGetCount( xSemaphore ) uxQueueMessagesWaiting( ( QueueHandle_t ) ( xSemaphore ) )参数1:计数信号量句柄
返回值:当前信号量的计数值大小

(三)互斥量

使用互斥信号量:首先将宏configUSE_MUTEXES置一
使用流程:创建互斥信号量 ->(task)获取信号量 ->(give)释放信号量
在这里插入图片描述

1、xSemaphoreCreateMutex()创建互斥量

#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )#define xSemaphoreCreateMutex() xQueueCreateMutex( queueQUEUE_TYPE_MUTEX )
#endif
返回值:互斥量的句柄

官方例子:

 Example usage:SemaphoreHandle_t xSemaphore;void vATask( void * pvParameters ){// Semaphore cannot be used before a call to xSemaphoreCreateMutex().// This is a macro so pass the variable in directly.xSemaphore = xSemaphoreCreateMutex();if( xSemaphore != NULL ){// The semaphore was created successfully.// The semaphore can now be used.}}

2、互斥信号量释放与获取同二值信号量

获取互斥量使用函数xSemaphoreTake(),释放信号量使用
函数xSemaphoreGive(),这两个函数的用法与获取和释放二值信号量一样。

注意1: 创建互斥信号量时,会主动释放一次信号量
注意2: 互斥信号量不支持中断中调用。
xSemaphoreGiveFromISR()和xSemaphoreTakeFromISR()不能应用于互斥量。
在这里插入图片描述

三、STM32Cube-FreeRTOS信号量实验后续更新

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/734240.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

宽度优先搜索算法(BFS)

宽度优先搜索算法(BFS)是什么? 宽度优先搜索算法(BFS)(也称为广度优先搜索)主要运用于树、图和矩阵(这三种可以都归类在图中),用于在图中从起始顶点开始逐层…

指针--2

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言1.指针运算1.1.指针-整数1.2.指针-指针1.3.指针的关系运算 2.野指针2.1 野指针成因2.2 如何规避野指针 3.assert 断言4.指针的使用和传址调用4.1 strlen的模拟实…

【Tauri】(4):整合Tauri和actix-web做本地大模型应用开发,可以实现session 登陆接口,完成页面展示,进入聊天界面

1,视频地址 https://www.bilibili.com/video/BV1GJ4m1Y7Aj/ 【Tauri】(4):整合Tauri和actix-web做本地大模型应用开发,可以实现session 登陆接口,完成页面展示,进入聊天界面 使用国内代理进行加…

6-DOF GraspNet: Variational Grasp Generation for Object Manipulation

总结: 使用变分自动编码器(VAE)对抓取进行采样,并使用基于点网的抓取评估器模型对采样的抓取进行评估和细化 摘要: 我们将抓取生成问题表述为 使用变分自编码器对一组抓取进行采样,并使用抓取评 估器模型对采样的抓取进行评估和…

备考2024年小学生古诗文大会:历年真题15题练习和独家解析

如何提高小学生古诗词的知识?如何激发小学生古诗词的学习兴趣?如何提高小学古诗词的学习成绩?如何备考2024年小学生古诗文大会?...如果你也在关心和这些问题,我的建议是参加每年一度的小学生古诗词大会(免费…

亚马逊跨境电商名词解释

亚马逊界面名词解释 最常用的名词解释总结: ASIN:亚马逊标准标识号,也就是每个商品的编码标识,每个商品的都不同,可以把它当成该商品的“身份证号”。由亚马逊随机生成的字母数字组合。 SKU:库存进出计量单位。 Listing&#xf…

太强了!最全的大模型检索增强生成(RAG)技术概览!

本文是对检索增强生成(Retrieval Augmented Generation, RAG)技术和算法的全面研究,对各种方法进行了系统性的梳理。文章中还包含了我知识库中提到的各种实现和研究的链接集合。 鉴于本文的目标是对现有的RAG算法和技术进行概览和解释&#…

django学习记录07——订单案例(复选框+ajax请求)

1.订单的数据表 1.1 数据表结构 1.2 数据表的创建 models.py class Order(models.Model):"""订单号"""oid models.CharField(max_length64, verbose_name"订单号")title models.CharField(max_length64, verbose_name"名称&…

做跨境电商,选哪个浏览器好?跨境电商浏览器推荐

在我们的日常生活中,有很多浏览器可供选择,比如百度浏览器、谷歌浏览器和360、火狐等等。但是在跨境电商行业中,是否有特别适合我们卖家使用的浏览器呢?所谓跨境电商浏览器,就是为跨境电商用户设计的浏览器&#xff0c…

Unity 采用自定义通道ShaderGraph实现FullScreen的窗户雨滴效果

效果如下 ShaderGraph实现 N21 随机化 DragLayer分层 将DragLayer分成四层,分别调整每层的缩放和大小 Shader实现的链接(Unity 雨水滴到屏幕效果) 我也是参考这个实现Shader Graph

微信小程序-侧滑删除

简介 movable-view和movable-area是可移动的视图容器,在页面中可以拖拽滑动。 本篇文章将会通过该容器实现一个常用的拖拽按钮功能。 使用效果 代码实现 side-view.wtml 布局见下面代码,left view为内容区域,right view为操作按钮&a…

初探深度学习-手写字体识别

前言 手写数字的神经网络识别通常指的是通过训练有素的神经网络模型来识别和分类手写数字图像的任务。这种类型的任务是机器学习和计算机视觉领域的一个经典问题,经常作为入门级的图像识别问题来展示和测试各种机器学习算法的能力。在实际应用中,手写数…

mac电脑总卡蓝屏是怎么回事,苹果电脑老卡蓝屏怎么办

电脑老卡蓝屏是比较常见的电脑故障之一,导致这一问题的出现很可能是电脑本身的硬件,或电脑上的驱动安装错误,没法运行,当然也不排除其他的一些因素。虽说电脑蓝屏是电脑几乎都会出现的小毛病,不足以致命,但…

基于决策树实现葡萄酒分类

基于决策树实现葡萄酒分类 将葡萄酒数据集拆分成训练集和测试集,搭建tree_1和tree_2两个决策树模型,tree_1使用信息增益作为特征选择指标,B树使用基尼指数作为特征选择指标,各自对训练集进行训练,然后分别对训练集和测…

图论练习6

[NOIP2013]车站分级 Here 解题思路 由于起始点之间所选的站号,相互之间一定满足那么对于起始点间未选择的站号,一定满足选择的站号考虑用边来维护信息,表示的级别大于按题意,则车站会被分为几个联通块,且保证块内无环…

So you think you understand IP fragmentation?

文章目录 前言一、Why care?二、Prevention三、Well-understood?四、Introducing fragquiz五、A novel (?) algorithm六、Reader challenge七、traceroute八、ICMP参考资料 前言 本文来自:https://lwn.net/Articles/960913/ February 7, 2024This article was …

【Python】成功解决ModuleNotFoundError: No module named ‘seaborn’

【Python】成功解决ModuleNotFoundError: No module named ‘seaborn’ 🌈 个人主页:高斯小哥 🔥 高质量专栏:Matplotlib之旅:零基础精通数据可视化、Python基础【高质量合集】、PyTorch零基础入门教程👈 …

高分辨率全球海洋温度和盐度再分析数据Global Ocean Physics Reanalysis(0.083°),并利用matlab读取绘图

1.引言 在研究全球海平面变化的问题中,卫星测高获得总的海平面变化,而海平面变化包含质量变化和比容变化。因此测高数据和海洋物理分析数据对于海平面研究至关重要。 测高数据下载网址: Global Ocean Gridded L 4 Sea Surface Heights And …

动态规划课堂4-----子数组系列

目录 引入: 例题1:最大子数组和 例题2:环形子数组的最大和 例题3:乘积最大子数组 例题4:乘积为正数的最长子数组 总结: 结语: 引入: 在动态规划(DP)子…

农场管理小程序|基于微信小程序的农场管理系统设计与实现(源码+数据库+文档)

农场管理小程序目录 目录 基于微信小程序的农场管理系统设计与实现 一、前言 二、系统设计 三、系统功能设计 1、用户信息管理 2、农场信息管理 3、公告信息管理 4、论坛信息管理 四、数据库设计 五、核心代码 七、最新计算机毕设选题推荐 八、源码获取&#x…