第14章——FreeRTOS信号量

news2024/9/22 14:29:48

1.信号量的简介

信号量是一种解决同步问题的机制,可以实现对共享资源的有序访问。

  • 信号量:用于传递状态(区别于队列传递消息)

  • 信号量的计数值都有限制:限定最大值。

  • 如果最大值被限定为1,那么它就是二值信号量;如果最大值不是1,它就是计数型信号量
    在这里插入图片描述

  • 当计数值大于0,代表有信号量资源

  • 当释放信号量,信号量计数值(资源数)加一

  • 当获取信号量,信号量计数值(资源数)减一
    在这里插入图片描述

2.二值信号量

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

  • xSemaphoreCreateBinary():使用动态方式创建二值信号量
  • xSemaphoreCreateBinaryStatic():使用静态方式创建二值信号量
  • xSemaphoreGive():释放信号量
  • xSemaphoreGiveFromlSR():在中断中释放信号量
  • xSemaphoreTake():获取信号量
  • xSemaphoreTakeFromISR():在中断中获取信号量
  • uxSemaphoreGetCount():获取信号量的计数值

2.1.创建二值信号量(动态)xSemaphoreCreateBinary()

SemaphoreHandle_t   xSemaphoreCreateBinary(void) 
#define   			xSemaphoreCreateBinary(void)
					xQueueGenericCreate(1, semSEMAPHORE_QUEUE_ITEM_LENGTH, queueQUEUE_TYPE_BINARY_SEMAPHORE )

#define semSEMAPHORE_QUEUE_ITEM_LENGTH      ( ( uint8_t ) 0U )
#define queueQUEUE_TYPE_BASE                ( ( uint8_t ) 0U )	/* 队列 */
#define queueQUEUE_TYPE_SET                 ( ( uint8_t ) 0U )	/* 队列集 */
#define queueQUEUE_TYPE_MUTEX               ( ( uint8_t ) 1U )	/* 互斥信号量 */
#define queueQUEUE_TYPE_COUNTING_SEMAPHORE  ( ( uint8_t ) 2U )	/* 计数型信号量 */
#define queueQUEUE_TYPE_BINARY_SEMAPHORE    ( ( uint8_t ) 3U )	/* 二值信号量 */
#define queueQUEUE_TYPE_RECURSIVE_MUTEX     ( ( uint8_t ) 4U )	/* 递归互斥信号量 */
  • 形参:无
  • 返回值:NULL,创建失败;其他值,创建成功返回二值信号量的句柄

2.2.释放信号量(通用)xSemaphoreGive()

BaseType_t	xSemaphoreGive(xSemaphore) 
#define   	xSemaphoreGive(xSemaphore)	
			xQueueGenericSend( ( QueueHandle_t ) ( xSemaphore ), NULL, semGIVE_BLOCK_TIME, queueSEND_TO_BACK)
#define   	semGIVE_BLOCK_TIME	( ( TickType_t ) 0U )
  • 形参xSemaphore:要释放的信号量句柄
  • 返回值:pdPASS,释放信号量成功;errQUEUE_FULL,释放信号量失败
  • 注意:释放信号量相当于写队列,但是当计数最大时无法阻塞,返回错误

2.3.获取信号量(通用)xSemaphoreTake()

BaseType_t	xSemaphoreTake( xSemaphore, xBlockTime ) 
#define 	xSemaphoreTake( xSemaphore, xBlockTime )    
			xQueueSemaphoreTake( ( xSemaphore ), ( xBlockTime ) )
BaseType_t 	xQueueSemaphoreTake( 	QueueHandle_t xQueue,
                                	TickType_t xTicksToWait )
  • 形参xSemaphore:要获取的信号量句柄
  • 形参xBlockTime:阻塞时间
  • 返回值:pdTRUE,获取信号量成功;pdFALSE,超时,获取信号量失败
  • 注意:获取信号量相当于读队列,同样可以阻塞

2.4.获取信号量的计数值(通用)uxSemaphoreGetCount()

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

2.5.二值信号量实验

  • 实验目的:学习 FreeRTOS 的二值信号量相关API函数的使用
  • 实验设计:将设计三个任务:start_task、task1、task2
    start_task-用来创建task1和task2任务
    task1-用于按键扫描,当检测到按键KEY0被按下时,释放二值信号量
    task2-获取二值信号量,当成功获取后打印提示信息
    在这里插入图片描述

3.计数型信号量

计数型信号量相当于队列长度大于1 的队列,因此计数型信号量能够容纳多个资源,这在计数型信号量被创建的时候确定的计数型信号量适用场合:

  • 事件计数:当每次事件发生后,在事件处理函数中释放计数型信号量(计数值+1),其他任务
    会获取计数型信号量(计数值-1) ,这种场合一般在创建时将初始计数值设置为 0
  • 资源管理:信号量表示有效的资源数目。任务必须先获取信号量(信号量计数值-1 )才能获取资源控制权。当计数值减为零时表示没有的资源。当任务使用完资源后,必须释放信号量(信号量计数值+1)。信号量创建时计数值应等于最大资源数目

API函数:

  • xSemaphoreCreateCounting() :使用动态方式创建计数信号量
  • xSemaphoreCreateCountingStatic() :使用静态方式创建计数信号量
  • xSemaphoreGive():释放信号量
  • xSemaphoreGiveFromlSR():在中断中释放信号量
  • xSemaphoreTake():获取信号量
  • xSemaphoreTakeFromISR():在中断中获取信号量
  • uxSemaphoreGetCount():获取信号量的计数值

3.1.创建计数信号量(动态)xSemaphoreCreateCounting()

#define	xSemaphoreCreateCounting(  uxMaxCount  ,  uxInitialCount  )
		xQueueCreateCountingSemaphore( (  uxMaxCount  ) , (  uxInitialCount  ) ) 
  • 形参uxMaxCount:计数值的最大值限定
  • 形参uxInitialCount:计数值的初始值
  • 返回值:NULL,创建失败;其他值,创建成功返回计数型信号量的句柄

3.2.计数型信号量实验

  • 实验目的:学习 FreeRTOS 的计数型信号量相关API函数的使用
  • 实验设计:将设计三个任务:start_task、task1、task2
    start_task-用来创建task1和task2任务
    task1-用于按键扫描,当检测到按键KEY0被按下时,释放计数型信号量
    task2-每过一秒获取一次计数型信号量,当成功获取后打印信号量计数值
    在这里插入图片描述

4.优先级翻转简介

优先级翻转:高优先级的任务反而慢执行,低优先级的任务反而优先执行
优先级翻转在抢占式内核中是非常常见的,但是在实时操作系统中是不允许出现优先级翻转的,因为优先级翻转会破坏任务的预期顺序,可能会导致未知的严重后果。 在使用二值信号量的时候,经常会遇到优先级翻转的问题。
在这里插入图片描述
解释:高优先级任务被低优先级任务阻塞,导致高优先级任务迟迟得不到调度。但其他中等优先级的任务却能抢到CPU资源。从现象上看,就像是中优先级的任务比高优先级任务具有更高的优先权(即优先级翻转)

5.互斥信号量

互斥信号量其实就是一个拥有优先级继承的二值信号量,在同步的应用中二值信号量最适合。互斥信号量适合用于那些需要互斥访问的应用中!
优先级继承:当一个互斥信号量正在被一个低优先级的任务持有时, 如果此时有个高优先级的任务也尝试获取这个互斥信号量,那么这个高优先级的任务就会被阻塞。不过这个高优先级的任务会将低优先级任务的优先级提升到与自己相同的优先级。
在这里插入图片描述
此时任务H的阻塞时间仅仅是任务L 的执行时间,将优先级翻转的危害降到了最低(注意没有消除)
优先级继承并不能完全的消除优先级翻转的问题,它只是尽可能的降低优先级翻转带来的影响 注意,互斥信号量不能用于中断服务函数中,原因如下:

  • 互斥信号量有任务优先级继承的机制, 但是中断不是任务,没有任务优先级, 所以互斥信号量只能用与任务中,不能用于中断服务函数。
  • 中断服务函数中不能因为要等待互斥信号量而设置阻塞时间进入阻塞态。

API函数:

  • xSemaphoreCreateMutex() :使用动态方式创建互斥信号量
  • xSemaphoreCreateMutexStatic() :使用静态方式创建互斥信号量
  • xSemaphoreGive():释放信号量
  • xSemaphoreTake():获取信号量
  • uxSemaphoreGetCount():获取信号量的计数值

【注意:使用互斥信号量:首先将宏configUSE_MUTEXES置一】

5.1.使用动态方式创建互斥信号量xSemaphoreCreateMutex()

#define   xSemaphoreCreateMutex(void)      xQueueCreateMutex( queueQUEUE_TYPE_MUTEX )
  • 返回值:NULL,创建失败;其他值,创建成功返回计数型信号量的句柄
  • 注意:创建互斥信号量时,会主动释放一次信号量

6.递归互斥信号量

递归互斥信号量可以看作是特殊的互斥信号量,与互斥信号量不同的是,递归互斥信号量在被获取后,可以被其持有者重复获取,当然递归互斥信号量的持有者需要释放递归互斥信号量与之获取递归互斥信号量相同的次数,递归互斥信号量才算被释放。
递归互斥信号量与互斥信号量一样,也具备优先级继承机制,因此也不能在中断服务函数中使用递归互斥信号量。

7.总结对比:队列、二值信号量、数值信号量、互斥信号量

二值信号量数值信号量互斥信号量总结
创建xSemaphoreCreateBinary()
xSemaphoreCreateBinaryStatic()
xSemaphoreCreateCounting()
xSemaphoreCreateCountingStatic()
xSemaphoreCreateMutex()
xSemaphoreCreateMutexStatic()
创建函数不同
底层均为队列创建函数
释放xSemaphoreGive()
xSemaphoreCreateBinaryStatic()
xSemaphoreGive()
xSemaphoreCreateBinaryStatic()
xSemaphoreGive()
释放函数相同
互斥信号量无中断释放
获取xSemaphoreTake()
xSemaphoreTakeFromISR()
xSemaphoreTake()
xSemaphoreTakeFromISR()
xSemaphoreTake()获取函数相同
互斥信号量无中断获取
取值uxSemaphoreGetCount()uxSemaphoreGetCount()uxSemaphoreGetCount()获取值函数相同
  • 二值信号量、计数信号量、互斥信号量的创建函数不同,但是释放和获取均相同,此外注意,互斥信号量在中断中无法使用,所有没有中断中释放/获取信号量
  • 二值信号量、计数信号量、互斥信号量的创建函数不同,但是底层调用的都是同一个API(队列创建函数),只是内部机制不同、某些参数不同,创建的信号量储存结构只有结构体,没有队列项,依靠变量uxMessagesWaiting储存信号量信息
  • 二值信号量、计数信号量、互斥信号量的释放信号量通用,底层调用与队列写入函数相同,只是参数不同
  • 二值信号量、计数信号量、互斥信号量的获取信号量通用,底层调用与队列写入函数不相同(类似),无buf参数

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

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

相关文章

多种编程语言运行速度排名-10亿次除7求余数为0的数量

最佳方式是运行10次,取平均数,用时秒数显示3位小数。 因为第一次打开,可能CPU还没优化好,多次取平均,比较准确 第1次共10次,用时3秒,平均3秒 第2次共10次,用时4秒,平均3.…

搭建开发环境-操作系统篇(一键搭建开发环境)

概述 所谓工欲善其事必先利其器,搭环境往往是开发过程中卡出很多初学者的拦路虎。 对于很多老鸟来说,很多东西都已经习惯成自然,也就没有刻意和初学者说。但对于很多初学者,却是受益良多。 这个系列,先从操作系统开始…

string类写时拷贝

文章目录 1.string类拷贝构造函数的现代写法2.string类写时拷贝vs和g下string结构的不同vs下string的结构:g下string的结构 3.总结 1.string类拷贝构造函数的现代写法 string类拷贝构造函数的传统写法: string(const string& s){if (this ! &s)…

2023年每天都投递很多份简历,但都石沉大海,我还投吗?测试人该何去何从?

各大互联网公司的接连裁员,政策限制的行业接连消失,让今年的求职雪上加霜,想躺平却没有资本,还有人说软件测试岗位饱和了,对此很多求职者深信不疑,因为投出去的简历回复的越来越少了。 另一面企业招人真的…

计算机视觉--利用HSV和YIQ颜色空间处理图像噪声

前言: Hello大家好,我是Dream。 今天我们将利用HSV和YIQ颜色空间处理图像噪声。在本次实验中,我们使用任意一张图片,通过RGB转HSV和YIQ的操作,加入了椒盐噪声并将其转换回RGB格式,最终实现对图像的噪声处理…

mysql之host is blocked问题

程序上线一段时间之后,更新程序总是遇到这个问题 每次都是重启几次程序,或者执行 flush hosts; 毕竟指标不治本,抽出时间决定分析一下问题,查阅了几篇博客。(感谢这几位大佬) https://blog.51cto.com/u_…

飞机打方块(四)游戏结束

一、游戏结束显示 1.新建节点 1.新建gameover节点 2.绑定canvas 3.新建gameover容器 4.新建文本节点 2.游戏结束逻辑 Barrier.ts update(dt: number) {//将自身生命值取整let num Math.floor(this.num);//在Label上显示this.num_lb.string num.toString();//获取GameCo…

数据结构—队列

队列 队列的概念及结构队列的实现 队列的概念及结构 队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out) 。 入队列:进行插入操作的一端称为队尾。 出队列&am…

Day8 智慧商城

项目演示 项目收获 创建项目 调整初始化目录 1.删components里的所有文件 2.删views里的所有文件 3.router/index.js 删路由 删规则 import Vue from vue import VueRouter from vue-routerVue.use(VueRouter)const router new VueRouter({routes: [] })export default route…

软件开发合同范本word文档,《某公司软件开发合同》,15页范本供参考

上一篇介绍了软件生命周期全过程,软件工程全周期全过程20项文档模板,附下载。从《合同》到《需求规格说明书》到软件设计、开发、实施、验收、维护等全过程相关文档模板。有朋友反馈附件内容没有补全,本次及后续会用实际案例补全附件内容&…

Backblaze 2023 Q2 硬盘故障质量报告解读

Backblaze 在其博客上发布了 2023 年第二季度的存储设备统计数据。这些数据包括了 Backblaze 在该季度所拥有的存储设备的数量、故障率和更换率等信息,这些信息对于了解存储设备的可靠性和性能非常有用。 在最新的Backblaze硬盘使用统计报告中,我们看到了…

OLED透明屏介绍:领先科技的革命性创新

OLED透明屏作为一项领先的科技创新,在产品设计和用户体验方面展现出了巨大的潜力。 在这篇文章中,尼伽将介绍OLED透明屏的定义、特点、应用领域以及未来发展趋势,以帮助您全面了解OLED透明屏。 一、OLED透明屏的定义与原理 1.1 定义&#x…

概念解析 | 走进射线管积分:探索数学与现实世界的神秘桥梁

注1:本文系“概念解析”系列之一,致力于简洁清晰地解释、辨析复杂而专业的概念。本次辨析的概念是:射线管积分。 走进射线管积分:探索数学与现实世界的神秘桥梁 射线管积分雷达成像 射线管积分(Ray Tube Integration&a…

leetcode 188. 买卖股票的最佳时机 IV

2023.8.21 这道题是 买卖股票的最佳时机III 的升级版&#xff0c;即买卖次数限制为k次&#xff0c;做法和上一篇如法炮制&#xff0c;直接看代码&#xff1a; class Solution { public:int maxProfit(int k, vector<int>& prices) {vector<vector<int>>…

Django模板语法,带你快速入门

目录 案例一&#xff1a;登录页面 案例二&#xff1a;for案例 if案例——单个字符串的传递&#xff0c;列表的传递&#xff0c;字典的传递 模板语法其本质&#xff1a;本质上&#xff0c;Django的模板语法就是在html中&#xff0c;写一些占位符&#xff0c;由数据对这些占位符…

6.824 lab2 raft实现

目录 1 难点及完成思路&#xff1a; 1.1 难点分析&#xff1a; 1.2 完成思路&#xff1a; 1.3 实验心得&#xff1a; 1.4 报告结构&#xff1a; 2 Leader选举模块 2.1 思路概括&#xff08;代码角度&#xff09; 2.2 注意问题&#xff1a; 2.3 代码细节&#…

[WMCTF 2023] crypto

似乎退步不了&#xff0c;这个比赛基本不会了&#xff0c;就作了两个简单题。 SIGNIN 第1个是签到题 from Crypto.Util.number import * from random import randrange from secret import flagdef pr(msg):print(msg)pr(br"""........ …

WMS仓库管理系统选择指南:如何确保您的仓库提高效率?

如何选择WMS仓库管理系统&#xff1f;仓库管理主要包括以下四个方面&#xff1a; 1.商品出入库管理 2.库存调拨 3.库存盘点 4.虚拟库存/实际库存管理 为了更好地管理仓库&#xff0c;我们需要确保基本的硬件设施得以满足&#xff0c;例如划分存储区域、使用货架以及进行员工培训…

Vivado2018.3版本_编译下载打包固化程序

Vivado2018.3版本_编译下载打包固化程序 概述&#xff1a; 在Vivado中开发导出硬件平台&#xff0c;然后在SDK中进行C语言的开发工作&#xff0c;然后把SDK编译生成的.elf文件加入Vivado工程中&#xff0c;编译生成.bit文件&#xff0c;转换成.mas文件&#xff0c;就可以固化到…

使用kubeadm工具升级kubernetes

一、背景&#xff1a; kubeadm部署的kubernetes集群进行升级&#xff0c;通常先升级控制节点&#xff0c;控制节点升级完成后再升级工作节点&#xff0c;本博文只升级了控制节点&#xff0c;工作节点按照相同的流程进行升级即可 环境说明&#xff1a; 主机名节点11.0.1.200k8s…