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信号量实验后续更新

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

FreeRTOS操作系统学习——FreeRTOS工程介绍

FreeRTOS工程介绍 核心文件 FreeRTOS的最核心文件只有2个: FreeRTOS/Source/tasks.cFreeRTOS/Source/list.c 文件功能如下图: 头文件相关 内存管理文件 文件在 Middlewares\Third_Party\FreeRTOS\Source\portable\MemMang 下,它也是放…

uniapp直接连接wifi(含有ios和安卓的注意事项)

前言 小程序中直接连接wifi-----微信小程序 代码 启动 //启动wifistartWifi() {return new Promise((resolve, reject) > {uni.startWifi({success: (res) > {console.log(启动wifi 成功, res)resolve(true)},fail: (err) > {console.error(启动wifi 失败, err)uni.s…

【教程】uni-app iOS打包解决profile文件与私钥证书不匹配问题

摘要 当在uni-app中进行iOS打包时,有时会遇到profile文件与私钥证书不匹配的问题。本文将介绍如何解决这一问题,以及相关的技术细节和操作步骤。 引言 在uni-app开发过程中,iOS打包是一个常见的操作。然而,有时会出现profile文…

SEMICON专题直播预告|一起聊聊半导体测试

2024年3月20日,全球最大规模半导体嘉年华——SEMICON China 2024将在上海新国际博览中心盛大启幕,作为半导体测试领域的领军企业,加速科技即将重装亮相此次盛会(N2馆N2327)。 在正式开展之前,加速科技将举…

2024年最受欢迎的15款缺陷管理工具

本文整理分享了15款再2024年受欢迎的bug(缺陷)跟踪管理工具:1.PingCode;2.Worktile;3.SpiraTeam;4. Jira Software;5. BugHerd;6. Zoho Projects;7.SmartSheet&#xff1…

腾讯云服务器5年优惠活动价格表(2核4G和4核8G)

腾讯云服务器网整理五年云服务器优惠活动 txyfwq.com/go/txy 配置可选2核4G和4核8G,公网带宽可选1M、3M或5M,系统盘为50G高性能云硬盘,标准型S5实例CPU采用主频2.5GHz的Intel Xeon Cascade Lake或者Intel Xeon Cooper Lake处理器,…

5G网络深度覆盖提升感知优化案例

随着5G业务的发展,用户感知尤为重要,随着人们的生活水平不断提高,对网络使用的要求也越来越高,用户感知更加重要,数据业务已超越语音业务成为流量和收入的主体,信号质量的决定作用更明显。5G TDD的频谱大带…

【CSP试题回顾】202203-2-出行计划

CSP-202203-2-出行计划 关键点:前缀和数组(高频考点) 详见:【CSP考点回顾】前缀和数组 解题思路 解法利用差分数组技巧,使得更新时间区间的操作和查询操作的时间复杂度都是 O(1),整体算法的时间复杂度主…

2024年最全洗地机选购攻略盘点丨希亦、小米、云鲸、海尔洗地机哪款值得入手?

在现代家居清洁中,洗地机是不可或缺的得力助手,它融合了吸尘、拖地等多种功能。面对市场上琳琅满目的洗地机品牌和型号,选择一个可靠的品牌至关重要。优质的品牌能够提供高品质的产品,使您的清洁工作更加轻松高效。本文将向您推荐…

基于多时间尺度的植被干旱响应特征与机制分析

随着全球气候变暖的趋势愈发明显,干旱事件不仅发生的频率增加,其持续时间和影响范围也在不断扩大。干旱对生态环境造成了严重破坏,导致生物多样性减少、土地退化和水资源短缺;对农业生产而言,干旱会导致作物减产甚至绝…

回溯算法04-组合总数(Java)

4.组合总数 题目描述 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。 candidates 中的 同一个 数字可以…

一张图串起来springcloud alibaba以及其他组件的作用,欢迎各位巨佬指正

一般来说,用一个gateway或者一个nginx应该够用,但是加上去好像也无妨 针对秒杀场景,有几种常见的解决方案: 基于Redis的缓存方案: 预热缓存:在秒杀开始前,将商品库存等信息提前加载到Redis缓存…

OSI七层模型/TCP四层模型

协议: 协议是双方共同指定的一组规则,在网络通信中表示通信双方传递数据和解释数据的一组规则。 从A上传文件到服务器B,需要在A和B之间制定一个双方都认可的规则,这个规则就叫文件传输协议,该协议是ftp协议的一个初级版本&#…

PySide6+VSCode Python可视化环境搭建

pip install pyside6 下载本期源码 vscode装一个PYQT Integration插件,设置好两个路径(下面有个脚本用于获取路径) 用everything的童鞋注意了:工具/选项/索引/强制重建 重启vscode可以看到,右击.ui文件时出现可以操作…

01-环境搭建、SpringCloud微服务(注册发现、服务调用、网关)

环境搭建、SpringCloud微服务(注册发现、服务调用、网关) 1)课程对比 2)项目概述 2.1)能让你收获什么 2.2)项目课程大纲 2.3)项目概述 随着智能手机的普及,人们更加习惯于通过手机来看新闻。由于生活节奏的加快,很多人只能利用碎片时间来获取信息&…

map和set(一)——关联式容器的常用接口使用及区别

一、关联式容器 在初阶阶段,我们已经接触过STL中的部分容器,比如:vector、list、deque、forward_list(C11)等,这些容器统称为序列式容器,因为其底层为线性序列的数据结构,里面 、存储的是元素本身。 那什么…

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"名称&…

Android6.0-14的兼容性

1.Android 6.0 ①新增运行时权限,危险权限需要动态申请 ②删除了对 Apache HTTP 客户端的支持, 解决方法:必须在build.gradle文件中声明以下编译时依赖项 android { useLibrary org.apache.http.legacy } 2.Android 8.0 ①允许安装未知来源…

15 实战:Kaggle房价预测 + 课程竞赛:加州2020年房价预测【李沐动手学深度学习课程笔记】

15 实战:Kaggle房价预测 课程竞赛:加州2020年房价预测【李沐动手学深度学习课程笔记】https://zhuanlan.zhihu.com/p/685343754 写在前面:这里格式很乱,代码直接去知乎copy 1 实战Kaggle比赛:预测房价 1.1 实现几个函…

C#实现选择排序算法

以下是使用C#实现选择排序算法的示例代码: using System;class SelectionSort {static void Main(string[] args){int[] arr { 64, 25, 12, 22, 11 };Console.WriteLine("排序前:");PrintArray(arr);SelectionSortAlgorithm(arr);Console.Wr…