本篇5K,立志最细,FreeRtos中的信号量Semaphore教程详解!!!
前言:本篇教程,参考韦东山,开发文档,连接放在最后
目录
Semaphore基本概念
二值信号量(Binary Semaphore)
计数信号量(Couting Semaphore)
互斥信号量(Mutex)
信号量释放和使用函数
Semaphore基本概念
信号量(Semaphore)是一种实现任务间通信的机制,可以实现任务之间的同步或者互斥访问,主要分为,二值信号量(Binary Semaphore),计数信号量(Couting Semaphore),互斥信号量(Mutex)。
与queue传输数据不同的是Semaphore利用本身信号量计数值用来传递决定Task能不能进行访问的状态,同时用这种状态来完成,Task的同步,互斥,限制访问资源Task数量。
信号量的API函数实际上使用的都是宏,使用来自现有的队列机制,二者也是有相似的地方的。
FreeRtos机制 | 队列(Queue) | 信号量(Semaphore) |
容纳数据 | 可以容纳多个数据 | 只能存放信号量计数值,对其进行操作 |
写操作 | Queue没有空间写数据可以阻塞 | 计数值最大时,返回不进入阻塞状态 |
读操作 | Queue中没有数据可以阻塞 | 没有信号量时可以阻塞 |
表格里面需要注意的是,信号量(Semaphore)在进行释放的时候,如果达到规定值,这个时候是没有阻塞状态的,只有等待信号量的时候有阻塞状态。
二值信号量(Binary Semaphore)
这种类型信号量,调用函数创建,信号量计数值默认初始化为0,同时计数值,取值只有0 或1 ,通常用来实现Task之间的互斥。
SemaphoreHandle_t xSemaphoreCreateBinary( void ); //动态创建
SemaphoreHandle_t xSemaphoreCreateBinaryStatic( StaticSemaphore_t *pxSemaphoreBuffer );//静态创建 需要结构体类型存储信号量
同样的Semaphore(信号量)的创建也分为动态创建和静态创建,区别也是静态创建需要结构体来存储数据。需要注意,这里在创建使用的时候,同时需要声明句柄,来创建,和后续通过句柄来完成对信号量的释放和使用操作。
static SemaphoreHandle_t Binary_Semaphore_Handle;//创建句柄承接创建函数的返回值
Binary_Semaphore_Handle = xSemaphoreCreateBinary();//使用函数创建二进制信号量
计数信号量(Couting Semaphore)
技术型信号量最大的特定是,创建的时候可以确定,信号量的最大值,与初始值,计数信号量,通常用来限制访问互斥资源的数量。
SemaphoreHandle_t xSemaphoreCreateCounting(UBaseType_t uxMaxCount, UBaseType_t uxInitialCount);// uxMaxCount: 信号量最大值 uxInitialCount 信号量初始值
SemaphoreHandle_t xSemaphoreCreateCountingStatic( UBaseType_t uxMaxCount, UBaseType_t uxInitialCount, StaticSemaphore_t *pxSemaphoreBuffer );
同样的计数型信号量的创建也分为动态创建和静态创建,区别也是静态创建需要创建存放信号量的数据结构。
static SemaphoreHandle_t counting_Semaphore_Handle; //创建句柄
counting_Semaphore_Handle = xSemaphoreCreateCounting(3,2);//信号量最大值为3,初始值为2的计数型信号量
这里调用需要注意的是,最大值是不能小于信号量的初始值的。
信号量 | 二进制信号量量 | 计数型信号量 |
动态创建 | xSemaphoreCreateBinary | xSemaphoreCreateCounting |
静态创建 | xSemaphoreCreateBinaryStatic | xSemaphoreCreateCountingStatic |
信号量初始值 | 二进制信号量初始值为0 | 计数型信号量初始值自己设定 |
释放申请删除 | 操作相同 | 操作相同 |
优先级反转问题
优先级反转指的是,高优先级任务因为等待低优先级任务释放信号量进入阻塞,低优先级任务被中优先级任务抢占了CPU,没有办法执行任务释放,信号量导致了整体的系统延迟的情况。
任务A(高优先级)
任务B(低优先级)
任务C(中优先级)
任务B持有资源:任务B(低优先级)首先获得了一个共享资源,比如某个互斥信号量,用于保护一个共享数据。
任务A请求资源:此时,任务A(高优先级)需要使用相同的共享资源,但由于任务B正在使用该资源,任务A必须等待任务B释放互斥信号量。于是,任务A进入阻塞状态,等待资源变得可用。
任务C抢占CPU:在任务A等待资源的同时,任务C(中优先级)不依赖该资源,但由于它的优先级高于任务B,它会在任务A和任务B之间获得CPU的执行机会,抢占任务B的CPU时间。
上面这种情况就会导致了,优先级反转问题的产生。
使用二进制信号量在多任务系统访问资源中,有概率会出现这个问题,需要防止这个问题的出现,当创建Task的时候可以尽量避免,中优先级的任务创建,或者使用互斥信号量后者的优先级继承问题可以有效的避免,优先级反转问题的出现。
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include "stdio.h"// 任务句柄
TaskHandle_t xHighPriorityTaskHandle, xMediumPriorityTaskHandle, xLowPriorityTaskHandle;// 信号量句柄
SemaphoreHandle_t xMutex;// 低优先级任务,持有共享资源
void vLowPriorityTask(void *pvParameters) {// 获取互斥信号量,模拟持有共享资源xSemaphoreTake(xMutex, portMAX_DELAY);printf("Low Priority Task: Obtained the mutex and using the resource.\n");// 模拟任务占用资源较长时间vTaskDelay(pdMS_TO_TICKS(2000));printf("Low Priority Task: Releasing the mutex.\n");// 释放互斥信号量xSemaphoreGive(xMutex);// 任务结束vTaskDelete(NULL);
}// 高优先级任务,等待获取共享资源
void vHighPriorityTask(void *pvParameters) {vTaskDelay(pdMS_TO_TICKS(500)); // 延迟以确保低优先级任务先执行printf("High Priority Task: Attempting to obtain the mutex...\n");// 试图获取互斥信号量xSemaphoreTake(xMutex, portMAX_DELAY);printf("High Priority Task: Obtained the mutex and using the resource.\n");// 模拟资源使用时间vTaskDelay(pdMS_TO_TICKS(1000));// 释放互斥信号量xSemaphoreGive(xMutex);printf("High Priority Task: Released the mutex.\n");// 任务结束vTaskDelete(NULL);
}// 中优先级任务,不需要共享资源,只是执行一段时间
void vMediumPriorityTask(void *pvParameters) {for (int i = 0; i < 5; i++) {printf("Medium Priority Task: Executing...\n");vTaskDelay(pdMS_TO_TICKS(500)); // 模拟占用CPU时间}// 任务结束vTaskDelete(NULL);
}int main(void) {// 创建互斥信号量xMutex = xSemaphoreCreateMutex();if (xMutex != NULL) {// 创建低优先级任务,优先级为1xTaskCreate(vLowPriorityTask, "Low Priority Task", configMINIMAL_STACK_SIZE, NULL, 1, &xLowPriorityTaskHandle);// 创建高优先级任务,优先级为3xTaskCreate(vHighPriorityTask, "High Priority Task", configMINIMAL_STACK_SIZE, NULL, 3, &xHighPriorityTaskHandle);// 创建中优先级任务,优先级为2xTaskCreate(vMediumPriorityTask, "Medium Priority Task", configMINIMAL_STACK_SIZE, NULL, 2, &xMediumPriorityTaskHandle);// 启动调度器vTaskStartScheduler();}// 如果代码运行到这里,说明调度器未能启动for(;;);
}
互斥信号量(Mutex)
互斥信号量(Mutex)是信号量的一种特殊类型,专门用来保护临界资源,确保只有一个任务可以访问该资源,特别的是互斥信号量拥有优先级继承机制,这种机制是二进制信号量和计数信号量没有的。
优先级继承机制特点在于,当低优先级人物持有互斥信号量,同时高优先级任务等待获取该信号量,低优先级任务会短暂提升自身优先级与高优先级任务优先级相同,直到释放互斥信号量,自身优先级会被取消,这个机制来保证因为任务优先级导致释放资源延迟程序的情况。
通常用于保护共享资源,防止任务并发访问。特别适合用于需要防止数据竞争的场景,并且系统中可能存在优先级反转问题的情况。
这种优先级集成机制,可以有效的避免优先级反转问题造成的,Task被阻止或者严重延迟。
SemaphoreHandle_t xSemaphoreCreateMutex( void );
SemaphoreHandle_t xSemaphoreCreateMutexStatic( StaticSemaphore_t *pxMutexBuffer );
上面是创建Mutex的原型函数,同样的静态创建需要定义结构体。
SemaphoreHandle_t Mutex_Handle; //声明句柄
Mutex_Handle = xSemaphoreCreateMutex();//创建Mutex
信号量操作函数
上文提及了,信号量不同的类型,当创建完信号量之后还要通过对信号量进行释放,使用,删除来完成特定任务。
BaseType_t xSemaphoreGive( SemaphoreHandle_t xSemaphore );//参数xSemaphore信号量句柄
BaseType_t xSemaphoreTake(SemaphoreHandle_t xSemaphore,TickType_t xTicksToWait);//xTicksToWait 0:不阻塞, portMAX_DELAY: 一直阻塞直到成功
这里需要注意的是使用信号量函数,多一个参数可选,可以选择阻塞等待信号量和不等待信号量,如果是在中断中使用则是下面的函数。
BaseType_t xSemaphoreGiveFromISR(SemaphoreHandle_t xSemaphore,BaseType_t *pxHigherPriorityTaskWoken);
BaseType_t xSemaphoreTakeFromISR(SemaphoreHandle_t xSemaphore,BaseType_t *pxHigherPriorityTaskWoken);
需要注意的是,在二进制信号量中,多次使用释放信号量函数,二进制信号量的值依旧是1,不会因为多次调用函数,从而导致信号量值的提高。
创建的信号量,在不需要的时候,同样的可以通过函数来删除,这里函数的参数是需要删除信号量的句柄。
void vSemaphoreDelete( SemaphoreHandle_t xSemaphore );//里面的参数填写句柄
欢迎指正,希望对你,有所帮助!!!
[9-2-2]_信号量实验_优先级反转_哔哩哔哩_bilibili
相关文章:
本篇5K,立志最细,FreeRtos中的信号量Semaphore教程详解!!!
前言:本篇教程,参考韦东山,开发文档,连接放在最后 目录 Semaphore基本概念 二值信号量(Binary Semaphore) 计数信号量(Couting Semaphore) 互斥信号量(Mutex&…...

【Postman】接口测试工具使用
干就完啦 Postman发送get请求案例1: Postman发送post请求案例2 Postman发送其他请求Postman测试实战 学习目标:能够使用Postman发送get/post/put/delete请求并获取响应结果 Postman发送get请求 首先postman是一款接口调试工具,支持win&…...

springboot 整合 rabbitMQ(1)
目录 一、MQ概述 二、MQ的优势和劣势 三、常见的MQ产品 RabbitMQ使用步骤 第一步:确保rabbitmq启动并且可以访问15672 第二步:导入依赖 第三步:配置 auto自动确认 manual手工确认(推荐使用!可以防止消息丢失&a…...

Appium Device Farm安装教程
环境要求:Appium version ≥ 2.4.X 安装appium npm install -g appium2.11.3 如果安装提示如下问题 npm error code EEXIST npm error syscall rename npm error path /Users/wan/.npm/_cacache/tmp/d5787519 npm error dest /Users/wan/.npm/_cacache/content-…...
异常、基类
异常 人生和世界总是充满着意外,争议、冲突和战争似乎是人类必然经历的过程。程序执行也有不满的时候。 不同编程语言的异常 Ada/Modula-3是早期引入异常处理的语言。 C语言没有标准意义的异常,使用goto或setjmp模拟错误或异常发生时的处理流程。 C/Java…...

VScode 自定义代码配色方案
vscode是一款高度自定义配置的编辑器, 我们来看看如何使用它自定义配色吧 首先自定义代码配色是什么呢? 看看我的代码界面 简而言之, 就是给你的代码的不同语义(类名, 函数名, 关键字, 变量)等设置不同的颜色, 使得代码的可读性变强. 其实很多主题已经给出了定制好的配色方案…...

MuMu模拟器12 KitsumeMask安装教程
这里是引用"> 在MuMu模拟器上安装KitsumeMask的时候遇到安装失败的情况。 一、下载APK安装包 如果你没有apk安装包可以通过下面的百度网盘进行下载 通过网盘分享的文件:KitsumeMask 链接: https://pan.baidu.com/s/1yeq3I6BsUD7J6uI-bnk-Vw?pwd=7n3v 提取码: 7n3v 二…...

Perforce静态分析工具2024.2新增功能:Helix QAC全新CI/CD集成支持、Klocwork分析引擎改进和安全增强
Perforce Helix QAC和Klocwork的最新版本对静态分析工具进行了重大改进,通过尽早修复错误、降低开发成本和加快发布速度,使开发团队实现左移。 本文中,我们将概述2024.2版本的新特性和新功能。 CI/CD和左移以实现持续合规性 现代软件开发实…...

太阳能电池特性及其应用
中南民族大学-通信工程2024-大学物理下实验 目录 代码实现结果显示 🛠工具使用 MarsCode(插件,集成在PyCharm); python编程(豆包AI智能体) 💻编程改进 此处是用「Matplotlib」来作图…...

日语学习零基础生活日语口语柯桥外语学校|股票用日语怎么说?
在日语中,“股票”可以说: • 株(かぶ) 这是最常用的表达方式,直接表示“股票”。 例如: 株を買う - 买股票 株を売る - 卖股票 • 株式(かぶしき) 这个词也是“股票”的意…...
第2关:寻找一个序列中的第K小的元素(即第k小元问题)
[TOC]寻找一个序列中的第K小的元素(即第k小元问题) 对于给定的含有n(n<100)元素的无序序列,求这个序列中第k(1≤k≤n)小的元素。 任务描述 本关任务:编写一个能计算数组中的第k小的元素的小程序。 相关…...

docker 搭建 vue3 + vite
vue3发布了,今天就分享一下我使用docker 搭建 vue3 vite 开发环境。至于为什么使用docker搭建,因为多版本可以快速切换,和本地环境避免冲突。好了话不多说我们开始吧。 1. 准备资料 Docker Desktop wsl2 ubuntu 下载地址 : https://www.docker.…...

【网易云音乐】--源代码分享
最近写了一个网易云音乐的音乐实现部分,是通过JavaScript和jQuery实现的,具体效果大家可以参照下面的视频 源代码分享 - git地址: 网易云音乐源代码 下面将着重讲解一下音乐实现部分 视频有点模糊,不好意思,在b站上添加视频的时候…...

股市大涨下的会展业创新者
近期,股市涨势强劲有力,各大指数普遍上扬,市场活力空前。与此同时,伴随全球经济逐步复苏及会展行业不断发展,上市展览公司机遇与挑战并存。国内外市场需求持续增长拓展了广阔发展空间,但同时行业竞争愈发激…...

工具篇-完整的 Git 项目管理工具教程(在命令框中使用 Git、在 IDEA 中使用 Git)
🔥博客主页: 【小扳_-CSDN博客】 ❤感谢大家点赞👍收藏⭐评论✍ 文章目录 1.0 Git 概述 2.0 Git 的安装和配置 3.0 获取本地仓库 3.1 基础操作指令 3.2 分支 4.0 Git 远程仓库 4.1 创建远程仓库 4.2 配置 SSH 公钥 4.3 操作远程仓库 5.0 使用…...

关于Amazon Linux 2023的版本及包管理器
在亚马逊上创建EC2实例时,会看到有一个Amazon Linux镜像。 那这个镜像与其他Linux有什么关系和区别呢? 网站是介绍:Amazon Linux 2023 是基于 Linux 的现代化通用操作系统,提供 5 年的长期支持。它针对 AWS 进行了优化࿰…...

Java面向对象编程--高级
目录 一、static关键字 1.1 静态变量 1.2 静态内存解析 1.3 static的应用与练习 二、单例设计模式 2.1 单例模式 2.2 如何实现单例模式 三、代码块 3.1 详解 3.2 练习,测试 四、final关键字 五、抽象类与抽象方法 5.1 abstract 5.2 练习 六、接口 6.…...

Vert.x,Web - 静态资源/模板
静态资源 Vert.x-Web带有开箱即用的处理器(StaticHandler),用于处理静态Web资源(.html, .css, .js, …), 因此可以非常轻松地编写静态Web服务器。 默认静态文件目录为类路径下的webroot目录,对于maven的项目,按规范放在src/main/…...

OpenAI今天Open了一下:开源多智能体框架Swarm
来源 | 机器之心 毫无疑问,多智能体肯定是 OpenAI 未来重要的研究方向之一,前些天 OpenAI 著名研究科学家 Noam Brown还在 X 上为 OpenAI 正在组建的一个新的多智能体研究团队招募机器学习工程师。 就在几个小时前,这个或许还没有组建完成的新…...

车辆重识别(2021NIPS无分类器扩散指南)论文阅读2024/10/08
[1] CLASSIFIER-FREE DIFFUSION GUIDANCE(无分类器扩散指导) (NIPS 2021) 作者:Jonathan Ho & Tim Salimans 单位:Google Research, Brain team(谷歌团队) 摘要: 分类器指导是最近引入的一…...
[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?
🧠 智能合约中的数据是如何在区块链中保持一致的? 为什么所有区块链节点都能得出相同结果?合约调用这么复杂,状态真能保持一致吗?本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里…...
<6>-MySQL表的增删查改
目录 一,create(创建表) 二,retrieve(查询表) 1,select列 2,where条件 三,update(更新表) 四,delete(删除表…...
golang循环变量捕获问题
在 Go 语言中,当在循环中启动协程(goroutine)时,如果在协程闭包中直接引用循环变量,可能会遇到一个常见的陷阱 - 循环变量捕获问题。让我详细解释一下: 问题背景 看这个代码片段: fo…...

通过Wrangler CLI在worker中创建数据库和表
官方使用文档:Getting started Cloudflare D1 docs 创建数据库 在命令行中执行完成之后,会在本地和远程创建数据库: npx wranglerlatest d1 create prod-d1-tutorial 在cf中就可以看到数据库: 现在,您的Cloudfla…...
前端倒计时误差!
提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...
Java如何权衡是使用无序的数组还是有序的数组
在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...

如何在看板中体现优先级变化
在看板中有效体现优先级变化的关键措施包括:采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中,设置任务排序规则尤其重要,因为它让看板视觉上直观地体…...

高等数学(下)题型笔记(八)空间解析几何与向量代数
目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...
css的定位(position)详解:相对定位 绝对定位 固定定位
在 CSS 中,元素的定位通过 position 属性控制,共有 5 种定位模式:static(静态定位)、relative(相对定位)、absolute(绝对定位)、fixed(固定定位)和…...
Axios请求超时重发机制
Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式: 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...