FreeRTOS信号量和互斥量

信息量

简介

信号量是一种解决同步问题的机制,可以实现对共享资源的有序访问。 前面介绍的队列(queue)可以用于传输数据:在任务之间、任务和中断之间。
消息队列用于传输多个数据,但是有时候我们只需要传递状态,这个状态值需要用一个数值表示。在这种情况下我们只需要维护一个数值,使用信号量效率更高、更节省内存。

特点

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

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

3、当获取信号量,信号量计数值(资源数)减一。

4、信号量:用于传递状态。

5、当信号量如果最大值被限定为1,那么它就是二值信号量;如果最大值不是1,它就是计数型信号量。

二进制信号量跟计数型信号量的区别

二进制信号量跟计数型的唯一差别,就是计数值的最大值被限定为1

信号量跟队列的对比

 这里的生产者指的是give信号量的任务,消费者是take信号量的任务。

信号量函数  

创建

        使用信号量之前,要先创建,得到一个句柄;使用信号量时,要使用句柄来表明使用哪个信号量。 对于二进制信号量、计数型信号量,它们的创建函数不一样:

                

 创建二进制信号量的函数原型如下:
/* 创建一个二进制信号量,返回它的句柄。
* 此函数内部会分配信号量结构体
* 返回值: 返回句柄,非 NULL 表示成功
*/
SemaphoreHandle_t xSemaphoreCreateBinary( void );
/* 创建一个二进制信号量,返回它的句柄。
* 此函数无需动态分配内存,所以需要先有一个 StaticSemaphore_t 结构体,并传入它的指
针
* 返回值: 返回句柄,非 NULL 表示成功
*/
SemaphoreHandle_t xSemaphoreCreateBinaryStatic( StaticSemaphore_t *pxSemaphoreBuffe
r );
创建计数型信号量的函数原型如下:
/* 创建一个计数型信号量,返回它的句柄。
* 此函数内部会分配信号量结构体
* uxMaxCount: 最大计数值
* uxInitialCount: 初始计数值
* 返回值: 返回句柄,非 NULL 表示成功
*/
SemaphoreHandle_t xSemaphoreCreateCounting(UBaseType_t uxMaxCount, UBaseType_t ux
InitialCount);
/* 创建一个计数型信号量,返回它的句柄。
* 此函数无需动态分配内存,所以需要先有一个 StaticSemaphore_t 结构体,并传入它的指
针
* uxMaxCount: 最大计数值
* uxInitialCount: 初始计数值
* pxSemaphoreBuffer: StaticSemaphore_t 结构体指针
* 返回值: 返回句柄,非 NULL 表示成功
*/
SemaphoreHandle_t xSemaphoreCreateCountingStatic( UBaseType_t uxMaxCount,
 UBaseType_t uxInitialCount,
 StaticSemaphore_t *pxSemaphoreBuffer );

删除

        对于动态创建的信号量,不再需要它们时,可以删除它们以回收内存。

        vSemaphoreDelete 可以用来删除二进制信号量、计数型信号量,函数原型如下:

/*
* xSemaphore: 信号量句柄,你要删除哪个信号量
*/
void vSemaphoreDelete( SemaphoreHandle_t xSemaphore );

获取信号量当前计数值大小 

uxSemaphoreGetCount( xSemaphore);

返回值:计数值。参数:信号量的句柄。 

give/take

        二进制信号量、计数型信号量的 give take 操作函数是一样的。这些函数也分为 2 个版本:给任务使用,给 ISR 使用。列表如下:

 xSemaphoreGive 的函数原型如下:

 BaseType_t xSemaphoreGive( SemaphoreHandle_t xSemaphore );

xSemaphoreGiveFromISR 函数的参数与返回值列表如下:

BaseType_t xSemaphoreGiveFromISR(SemaphoreHandle_t xSemaphore, BaseType_t *pxHigherPriorityTaskWoken);        

xSemaphoreTake 函数的参数与返回值列表如下 :

BaseType_t xSemaphoreTake(SemaphoreHandle_t xSemaphore, TickType_t xTicksToWait);

 

xSemaphoreTakeFromISR 的函数原型如下:

 BaseType_t xSemaphoreTakeFromISR( SemaphoreHandle_t xSemaphore, BaseType_t *pxHigherPriorityTaskWoken);

这里有一点需要读者留意,ISR函数里面有一个BaseType_t*pxHigherPriorityTaskWoken ,和相对另一个参数TickType_t xTicksToWait却不一样,这里是因为,在中断里面调用take ,因为中断无法被阻塞,我们不能设置需要等待的tick,我们会设置这个参数,来告诉是否有任务因为中断读取信号量而变成了就绪态,之后根据这个值,决定是否进行任务调度,去切换任务。 

主要作用:优先级翻转

简介:优先级翻转:高优先级的任务反而慢执行,低优先级的任务反而优先执行。
实质:无非就是高优先级的任务take信号量失败,导致自己被阻塞,然后低优先级任务乘虚而入,等到低优先级任务执行完,才释放信号量,高优先级任务才得以take到信号量,回到ready状态。
总结:高优先级任务被低优先级任务阻塞,导致高优先级任务迟迟得不到调度。但其他中等优先级的任务却能抢到CPU资源。从现象上看,就像是中优先级的任务比高优先级任务具有更高的优先权(即优先级翻转)。

 互斥量 

简介

互斥信号量其实就是一个拥有优先级继承的二值信号量,在同步的应用中二值信号量最适合。互斥信号量适合用于那些需要互斥访问的应用中!

优先级继承

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

互斥量的使用场合

        在多任务系统中,任务 A 正在使用某个资源,还没用完的情况下任务 B 也来使用的话,就可能导致问题。
        比如对于串口,任务A 正使用它来打印,在打印过程中任务 B 也来打印,客户看到的结果就是A B 的信息混杂在一起。
        上述问题的解决方法是:任务A 访问这些全局变量、函数代码时,独占它,就是上个锁。这些全局变量、函数代码必须被独占地使用,它们被称为临界资源。
         互斥量也被称为互斥锁,使用过程如下:

 互斥量函数

创建   

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

使用互斥量时,先创建、然后去获得、释放它。使用句柄来表示一个互斥量。 创建互斥量的函数有2种:动态分配内存,静态分配内存,函数原型如下:

动态分配内存:

/* 创建一个互斥量,返回它的句柄。
* 此函数内部会分配互斥量结构体
* 返回值: 返回句柄,非 NULL 表示成功
*/
SemaphoreHandle_t xSemaphoreCreateMutex( void );

 静态分配内存:

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

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

 删除

/*
* xSemaphore: 信号量句柄,你要删除哪个信号量, 互斥量也是一种信号量
*/
void vSemaphoreDelete( SemaphoreHandle_t xSemaphore );

 释放

BaseType_t xSemaphoreGive( SemaphoreHandle_t xSemaphore );

 获得

BaseType_t xSemaphoreTake(SemaphoreHandle_t xSemaphore, TickType_t xTicksToWait);

 互斥量不能在ISR中使用

原因如下:
(1) 互斥信号量有任务优先级继承的机制, 但是中断不是任务,没有任务优先级, 所以互斥信号量只能用与任务中,不能用于中断服务函数。
(2) 中断服务函数中不能因为要等待互斥信号量而设置阻塞时间进入阻塞态。
FreeRTOS 提供了专门用于在 ISR 中操作的函数,如 xSemaphoreGiveFromISR 和  xSemaphoreTakeFromISR,这些函数经过设计以确保在 ISR 上下文中操作信号量的安全性和有效性。这些函数在实现上会考虑到互斥量的特殊性和需求。
        

总结

信号量:

信号量就是特殊的队列。

队列里使用环形缓冲区存放数据,

信号量里只记录计数值

互斥量:

互斥量就是特殊的队列。

互斥量更是特殊的信号量,

互斥量实现了优先级继承

至于信号量和互斥量的内部机制,我们可以知道,他们都是特殊的队列,实际上和队列的内部机制几乎一样,如果想要了解,可以去看我FreeRTOS消息队列,里面有队列的内部机制讲解。

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

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

相关文章

并发编程基础概念

相关概念 并行 并行是指同一个时刻,多个任务同时进行。只有在多核CPU下才会发生。 并发 并发是指单个CPU在不同任务之间来换切换工作,但是同一时刻只有一个任务在工作。由于CPU的切换速度很快,给人的感受是多个任务在一起运行。 串行 串行…

破解对LabVIEW的偏见

LabVIEW被广泛应用于科学研究、工程测试和自动化控制领域,具有专业性和高效的开发能力。尽管有人对其存在偏见,认为不如C语言,但LabVIEW的图形化编程、强大集成能力、丰富社区支持和专业功能,使其在许多实际应用中表现出色。通过多…

山东大学-科技文献阅读与翻译(期末复习)(选择题+翻译)

目录 选择题 Chapter1 1.which of the following is not categorized as scientific literature 2.Which of the followings is defined as tertiary(三级文献) literature? 3.Which type of the following international conferences is listed as Number one conference…

jeecg启动微服务并注册到本地nacos

1、maven勾选环境和微服务模式,并刷新 2、pom文件修改nacos注册地址 3、本地启nacos gateway 和自己想要的cloud下面的模块pos sys 4、打断点测试接口,访问gateway端口和想要测试的地址

Java-记一次Springboot版本升级导致的问题

前言 根据相关情况,需要将SpringBoot的版本由原来的2.1.8.RELEASE版本升级至2.3.8.RELEASE。 启动项目后报错: 具体报错信息如下: Description: An attempt was made to call a method that does not exist. The attempt was made from the…

互联网信任危机:Perplexity搜索引擎如何破坏内容创作者的权益

前段时间,Perplexity搜索引擎还是一颗冉冉升起的明日之星,手握巨额投资,有很美好的未来前景,这时,如果不出意外的话,要出意外。 喜好儿网 Perplexity这家公司,它正试图通过创建一个新型的“答…

UI设计必备的6个网站,赶紧收藏!

6个UI设计必备网站,找素材、找灵感一步到位,赶紧收藏起来吧! 1、菜鸟图库 UI图片素材-UI图片模板免费下载 - 菜鸟图库 菜鸟图库提供了超多免费设计素材,在这里你可以找到平面、UI、电商等设计类素材,还有大量的高清背…

数字信号处理实验四(FIR数字滤波器设计)

FIR数字滤波器设计(2学时) 要求: 设计一个最小阶次的低通FIR数字滤波器,性能指标为:通带0Hz~1500Hz,阻带截止频率2000Hz,通带波动不大于1%,阻带波动不大于1%,采样频率为8…

杂谈咋说-事业编与公务员建议收藏!

杂谈咋说-事业编与公务员建议收藏! 什么是铁饭碗 在中国,「铁饭碗」这个词常常被用来形容那些稳定、有保障的工作。 当我们谈论"铁饭碗"时,人们往往会将公务员和事业编制人员进行比较。 尽管这两者都是相对稳定的工作&#xff…

Cesium 在加载 3dTiles 如何如何获取ID

文章目录 问题分析问题 加载的 3dTiles 打印content.getFeature(i)出来后如图所示,想获取到id值 分析 var tileset = mapLayer.init3dTileLayer({url:it.url,maximumMemoryUsage: it.maximumMemoryUsage,

golang使用RSA加密和解密

目录 前提 生成RSA公钥和密钥 读取文件 加密 解密 前提 本文章我们是先读取的RSA文件,所以需要先生成RSA,并且保存在文件中,再进行加密 生成RSA公钥和密钥 如果没有公钥和密钥,可以先看看我上一篇文章 生成RSA公钥和密钥h…

一个AI图片生成工具导航网站

上周末上线了一个AI图片生成工具导航网站,主要是面向AI图片工具这个垂直领域。 https://chatgpt-image-generator.com/ 目标是通过收集当下的一些工具,然后进行分类管理,一方面方便大家发现新的工具,另一方面能够更加有针对性、…

Kotlin vs Java:深入解析两者之间的最新差异与优劣(全面指南)

文章目录 1. 概述2. 语法简洁性3. 空安全4. 扩展函数5. 协程6. 数据类7. 智能类型转换8. 默认参数与命名参数9. 无 checked exceptions10. 单例模式总结 🎉欢迎来到Java学习路线专栏~探索Java中的静态变量与实例变量 ☆* o(≧▽≦)o *☆嗨~我是IT陈寒🍹✨…

python CSSE7030

1 Introduction In this assignment, you will implement a (heavily) simplified version of the video game ”Into The Breach”. In this game players defend a set of civilian buildings from giant monsters. In order to achieve this goal, the player commands a s…

上位机图像处理和嵌入式模块部署(mcu之静态库生成和使用)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing 163.com】 很多同学做了很长时间的mcu和keil开发,都认为keil工程中必须包含所有的源代码,其实这是不对的。如果有一些代码我们不希望别…

游戏AI的创造思路-技术基础-深度学习(7)TF

重头戏TF,汽车人,变形~~~~ 现在广泛应用的GPT中,数据处理的关键点就是Transformer算法,多次多层的映射“变形”造就了其对自然语言处理能力的提升,但本篇介绍的内容中,Transformer算法是用来构建游戏AI的“…

深度学习经典检测方法概述

一、深度学习经典检测方法 two-stage(两阶段):Faster-rcnn Mask-Rcnn系列 one-stage(单阶段):YOLO系列 1. one-stage 最核心的优势:速度非常快,适合做实时检测任务! 但是…

【知识图谱系列】(实例)python操作neo4j构建企业间的业务往来的知识图谱

本章节通过聚焦于"金额"这一核心属性,构建了一幅知识图谱,旨在揭示"销售方"与"购买方"间的商业互动网。在这张图谱中,绿色节点象征着购买方,而红色节点则代表了销售方。这两类节点间的紧密连线,不仅映射了双方在市场活动中的合作桥梁,还特…

8个成功的原型设计案例分享

原型设计在整个产品设计过程中非常的重要,定下了整个产品的基调,想要做好原型设计,需要不断的经验的积累,新手入门最快的方式就是学习一些优秀的原型设计案例,今天就为大家分享一些可以直接使用源文件进行编辑和修改的…

Linux高级编程——线程

pthread 线程 概念 :线程是轻量级进程,一般是一个进程中的多个任务。 进程是系统中最小的资源分配单位. 线程是系统中最小的执行单位。 优点: 比多进程节省资源,可以共享变量 进程会占用&am…