信号量(semaphore)

一、信号量简介

       前面介绍的消息队列主要用于传输数据:任务与任务之间、任务与中断之间

       在有些情况下,不需要传输数据,只需要传递状态即可

                • 车开出停车位,你的车可以停进来了

                • 课已经录制完成,你可以进行观看了

1.1 信号量的含义

        信号量是一种实现任务间通信的机制可以实现任务之间的同步临界资源的互斥访问,可以实现对共享资源的有序访问(用于传递状态

共享资源的访问:

※ 案列一:汽车驶入或离开停车位,停车位的个数(计数型信号量)

※案列二:公共电话的使用(二值信号量)

        

任务之间的同步(任务与任务、任务与中断):

        在执行中断服务函数的时候,可以通过释放信号量(不做具体的处理,以提高系统的实时性)来通知某个任务所期待的事件发生了。当退出中断后,通过调度器,同步的任务(做出相应的处理)就会执行

        信号量用于控制共享资源的访问的场景相当于一个上锁机制,只有获得这把锁的钥匙才可以进行下一步操作

Q:既然队列也可以实现同步与互斥那为什么还要信号量?
答:信号量相比队列更节省空间,因为实现同步与互斥不需要传递数据,所以信号量没有队列后面的环形存储区,信号量主要就是依靠计数值uxMessagesWaiting(在队列中表示队列现有消息个数,在信号量中表示有效信号量个数)。

           当计数值 > 0,代表信号量有资源

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

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

        

 信号:通知某个对象

  量:资源的数量:计数值都有限制

         • 限定最大值是1,则是二进制信号量

         • 限定最大值不是1,则是计数值信号量

FreeRTOS中信号量又分为二值信号量、计数型信号量、互斥信号量和递归互斥信号量

总结:信号量是用于传递状态

1.2 队列与信号量的对比

队列

信号量

可以容纳多个数据

创建队列有两部分内存:队列结构体+队列项存储空间

仅存放计数值,无法存放其他数据;

创建信号量,只需分配信号量结构体

写入队列:当队列满时,可阻塞

释放信号量:不可阻塞,计数值++

当计数值为最大值时,返回失败

读取队列:当队列为空时,可阻塞

获取信号量:计数值--

当没有资源时,可阻塞

1.3 二值信号量与计数型信号量的区别

二值信号量计数型信号量
队列长度1大于1
资源初始化0可以根据情况设定

 二、二值信号量

二值信号量的本质:一个队列长度为 1 ,队列项大小为0队列 ,该队列就只有空和满两种情况

        二值信号量通常用于互斥访问或任务同步与互斥信号量(拥有优先级继承)比较类似,但是二值信号量有可能会导致优先级翻转的问题 ,所以二值信号量更适合用于同步(任务与任务、任务与中断)

         同步:所有任务排着队一件件的往后进行,上件事情没有完成,就继续做上件事情,等上件事情完成后才会去做下一件事情

 使用二值信号量的过程创建二值信号量 ——> 释放二值信号量(队满) ——> 获取二值信号量(队空)     

:创建二值信号量时,初始值为0,所以先要释放信号量

2.1 二值信号量相关API函数

头文件:semphr. h

函数

描述

xSemaphoreCreateBinary()

使用动态方式创建二值信号量

xSemaphoreCreateBinaryStatic()

使用静态方式创建二值信号量

xSemaphoreGive()

释放信号量

xSemaphoreGiveFromISR()

在中断中释放信号量

xSemaphoreTake()

获取信号量

xSemaphoreTakeFromISR()

在中断中获取信号量

 注:二值、计数型、互斥信号量释放与获取均用这两个函数 

 2.1.1 动态创建二值信号量:

实质:创建一个长度为1、队列项大小为0的队列

 2.1.2 释放信号量函数:

※ 对于信号量而言,释放不允许设置阻塞时间,如果队列已满,则直接返回

入队方式:向后入队

 2.1.3 获取信号量函数: 

※ 对于信号量而言,获取允许设置阻塞时间,如果队列为空,则可以选择是否进行等待

可以看出:二值信号量的API函数与队列操作的函数相同,区别只是入口参数不同 

 三、计数型信号量

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

计数型信号量常用于:事件计数、资源管理

注:不同适用场合,信号量创建时的计数值不同

3.1 计数值信号量相关API函数

函数

描述

xSemaphoreCreateCounting()

使用动态方法创建计数型信号量。

xSemaphoreCreateCountingStatic()

使用静态方法创建计数型信号量

uxSemaphoreGetCount()

获取信号量的计数值

             计数型信号量的释放和获取与二值信号量相同 !

3.1.1 动态创建计数值信号量

3.1.2  获取当前计数值

四、互斥信号量(mutex)

4.1 优先级反转:

前面说到,二值信号量用于互斥访问时,会出现优先级反转的情况 

优先级翻转:高优先级的任务反而慢执行,低优先级的任务反而优先执行

        高优先级任务被低优先级任务阻塞,导致高优先级任务迟迟得不到调度。但其他中等优先级的任务却能抢到CPU资源。从现象上看,就像是中优先级的任务比高优先级任务具有更高的优先权(即优先级翻转) 

4.2 互斥信号量

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

4.2.1 优先级继承

        优先级继承:暂时提高某个占有某种资源的低优先级任务的优先级,使之与在所有等待该资源的任务中优先级最高那个任务的优先级相等,而当这个低优先级任务执行完毕释放该资源时,优先级重新回到初始设定值

         当任务L获取信号量后,还没来得及释放,就被高优先级的任务抢占,但没有信号量,高优先级任务H就进入阻塞,此时任务L运行,并将任务L的优先级设置为与任务H同等优先级,即使任务M就绪,也不会得到执行,直到L释放信号量,H获取信号量,任务H开始运行

        此时任务H的阻塞时间仅仅是任务L 的执行时间将优先级翻转的危害降到了最低。优先级继承并不能完全的消除优先级翻转的问题,它只是尽可能的降低优先级翻转带来的影响

总结:

所谓优先级继承,其实就是低优先级任务继承高优先级任务的优先级
发生优先级继承:在高优先级任务获取信号量失败(低优先级任务已经持有信号量)进入阻塞态之前,将持有信号量的低优先级任务的优先级提升

解除优先级继承:在持有信号量的低优先级任务释放信号量的时候,将自己的优先级恢复到初始值(因为已经释放了信号量,完成了任务)

4.3 互斥信号量相关API函数

使用流程:创建互斥信号量 ——> (task获取信号量 ——>(give)释放信号量 

注意:创建互斥信号量时,会主动释放一次信号量

使用互斥信号量:首先将宏configUSE_MUTEXES置1

函数

描述

xSemaphoreCreateMutex()

使用动态方法创建互斥信号量。

xSemaphoreCreateMutexStatic()

使用静态方法创建互斥信号量。

 4.3.1 动态创建互斥信号量

互斥信号量的释放和获取函数与二值信号量相同

        只不过互斥信号量由于涉及到任务优先级继承的性质,而中断不属于任务,没法处理中断由新阿基继承,因此不支持中断中调用

五、递归互斥信号量

5.1 互斥信号的缺点

(1)不能实现由A获取就由A释放

比如:任务A、B互斥访问串口打印资源,假如任务A已经获取,还没释放。此时,任务C偷偷释放,使得资源失去保护,任何任务都可以访问该资源,会发生混乱

(2)死锁

比如:任务A进行两次获取,第二次获取必定失败,导致任务被阻塞,其他任务想要获取,该任务还未释放,导致死锁

5.2 递归互斥信号量

        递归互斥信号量是一种特殊的互斥信号量。已经获取了递归互斥信号量的任务可以再次获取这个递归互斥信号量(即可以嵌套使用),且次数不限。一个任务获取了多少次递归互斥信号量就必须释放多少次释放之前递归互斥量都处于无效状态其他任务无法获取只有持有递归信号量的任务才能获取和释放

     

  递归互斥信号量不能在中断函数中使用 

5.3 递归互斥信号量相关API函数

5.3.1 动态创建

使用条件:configSUPPORT_DYNAMIC_ALLOCATION 和 configUSE_RECURSIVE_mutexes 都必须在 FreeRTOSConfig.h 中定义为 1

SemaphoreHandle_t xSemaphoreCreateRecursiveMutex( void )

返回值:

成功:返回创建的互斥锁的句柄

失败:返回 NULL

 SemaphoreHandle_t xMutex;void vATask( void * pvParameters ){Create a recursive mutex.xMutex = xSemaphoreCreateRecursiveMutex();if( xMutex != NULL ){/* The recursive mutex was created successfully andcan now be used. */}}

注:

使用流程:创建递归互斥信号量 ——> (task获取信号量 ——>(give)释放信号量 

注意:创建递归互斥信号量时,会主动释放一次信号量

 

5.3.2 获取递归互斥信号量

使用条件:configUSE_RECURSIVE_MUTEXES 设置为 1

xSemaphoreTakeRecursive( SemaphoreHandle_t xMutex,TickType_t xTicksToWait );

 SemaphoreHandle_t xMutex = NULL;// A task that creates a mutex.void vATask( void * pvParameters ){// Create the mutex to guard a shared resource.xMutex = xSemaphoreCreateRecursiveMutex();}// A task that uses the mutex.void vAnotherTask( void * pvParameters ){// ... Do other things.if( xMutex != NULL ){// See if we can obtain the mutex.  If the mutex is not available// wait 10 ticks to see if it becomes free.    if( xSemaphoreTakeRecursive( xMutex, ( TickType_t ) 10 ) == pdTRUE ){xSemaphoreTakeRecursive( xMutex, ( TickType_t ) 10 );xSemaphoreTakeRecursive( xMutex, ( TickType_t ) 10 );xSemaphoreGiveRecursive( xMutex );xSemaphoreGiveRecursive( xMutex );xSemaphoreGiveRecursive( xMutex );// Now the mutex can be taken by other tasks.}else{// We could not obtain the mutex and can therefore not access// the shared resource safely.}}}

 5.3.3 释放递归互斥信号量

使用条件:将 configUSE_RECURSIVE_MUTEXES 设置为 1

xSemaphoreGiveRecursive( SemaphoreHandle_t xMutex )

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

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

相关文章

【一】m2芯片的mac中安装ubuntu24虚拟机集群

文章目录 1. 虚拟机配置2. 复制虚拟机2.1 修改主机名2.2 修改网络 1. 虚拟机配置 在官方网站下载好ubuntu24-arm版镜像开始安装,安装使用VMWare Fusion的社区免费授权版,使用一台m2芯片的mac电脑作为物理机平台。 为什么选择ubuntu24?因为centOS7目前已…

Android 如何通过代码实时设置EditTextView光标

背景:换肤框架下,QA进行深色浅色切换说输入框光标颜色没有改变,转UI结果UI说需要修改!!!!! 本来有方法可以设置,但是 设置后未生效。重新进入该页面才生效!&a…

windows电脑如何运行python的定时任务

这里需要使用:windows系统设置-控制面板里的计划任务 1.打开计划任务之后,选择:创建基本任务 2.填写名称,这里根据自己具体的项目需求填写,然后点击下一步。 3.选择每日,再点击下一步 4.设置时间&…

vue3长列表优化,使用vue-virtual-scroller实现直播间弹幕列表虚拟滚动效果

使用的组件库是:https://github.com/Akryum/vue-virtual-scroller 官方文档:vue-virtual-scroller 安装依赖 npm install --save vue-virtual-scrollernextpnpm install --save vue-virtual-scrollernextyarn add vue-virtual-scrollernext 组件导入…

简过网:教师编制报考要求和条件,都给你汇总好了!

如果你想要考教师编,那么在考试之前你先要明白这些知识! ​ 一、什么是教师编? 在编教师拥有的编制为事业编,即在编老师为事业单位工作人员 二、考教师编需要什么条件? 1、普通话 语文学科普通话要求达到二级甲等及…

重定向与转发

转发参数不会自动包含在新的请求中。若要将参数传递给重定向地址,可以在服务器端显式地添加参数到重定向URL中。 在重定向URL中包含参数 import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; impor…

Python + 在线 + 文生音,音转文(中文文本转为英文语音,语音转为中文文本)

开源模型 平台:https://huggingface.co/ars-语言转文本: pipeline("automatic-speech-recognition", model"openai/whisper-large-v3", device0 ) hf: https://huggingface.co/openai/whisper-large-v3 github: https://github.com/openai/wh…

JAVA--JSON转换工具类

JSON转换工具类 import com.alibaba.fastjson.JSONObject; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackso…

C++:特殊类的设计(无线程)

目录 一、设计一个不能拷贝类 二、设计一个只能在堆上创建对象的类 方法一:析构函数私有化 方法二:构造函数私有化 三、设计一个只能在栈上创建对象的类 四、设计一个类不能被继承 五、设计一个只能创建一个对象的类(单例模式&#xf…

【MySQL】mysql访问

mysql访问 1.引入MySQL 客户端库2.C/C 进行增删改3.查询的处理细节4.图形化界面访问数据库4.1下载MYSQL Workbench4.2MYSQL Workbench远程连接数据库 点赞👍👍收藏🌟🌟关注💖💖 你的支持是对我最大的鼓励&a…

通过端口和进程pid查找启动文件/脚本

今天审计一个程序又让GPT给我上了一课,记一下笔记: 1、首先该程序开启了8080端口,使用如下命令得到pid为1817 netstat -tunlp|grep 80802、使用pid得到父进程 pstree -ps 1817输出结果如下: 3、看出程序是由systemd启动的&…

[单master节点k8s部署]19.监控系统构建(四)kube-state-metrics

kube-state-metrics 是一个Kubernetes的附加组件,它通过监听 Kubernetes API 服务器来收集和生成关于 Kubernetes 对象(如部署、节点和Pod等)的状态的指标。这些指标可供 Prometheus 进行抓取和存储,从而使你能够监控和分析Kubern…

钡铼RTU无线S270用于风力发电站机房远程状态监测和故障预警系统集成

在现代风力发电行业中,机房的远程监测和故障预警系统对于保障风力发电机组的稳定运行至关重要。钡铼第4代S270工业级4G远程遥测终端(RTU),以其先进的技术和多功能应用,成为风力发电站机房智能化管理的理想选择。 技术…

【MySQL备份】Percona XtraBackup总结篇

目录 1.前言 2.问题总结 2.1.为什么在恢复备份前需要准备备份 2.1.1. 保证数据一致性 2.1.2. 完成崩溃恢复过程 2.1.3. 解决非锁定备份的特殊需求 2.1.4. 支持增量和差异备份 2.1.5. 优化恢复性能 2.2.Percona XtraBackup的工作原理 3.注意事项 1.前言 在历经了详尽…

uni-app组件 子组件onLoad、onReady事件无效

文章目录 导文解决方法 导文 突然发现在项目中,组件 子组件的onLoad、onReady事件无效 打印也出不来值 怎么处理呢? 解决方法 mounted() {console.log(onLoad, this.dateList);//有效// this.checkinDetails()},onReady() {console.log(onReady, this.da…

百度云智能媒体内容分析一体机(MCA)建设

导读 :本文主要介绍了百度智能云MCA产品的概念和应用。 媒体信息海量且复杂,采用人工的方式对视频进行分析处理,面临着效率低、成本高的困难。于是,MCA应运而生。它基于百度自研的视觉AI、ASR、NLP技术,为用户提供音视…

【C++】哈希表 ---开散列版本的实现

你很自由 充满了无限可能 这是很棒的事 我衷心祈祷你可以相信自己 无悔地燃烧自己的人生 -- 东野圭吾 《解忧杂货店》 开散列版本的实现 1 前言2 开散列版本的实现2.1 节点设计2.2 框架搭建2.3 插入函数2.4 删除函数2.5 查找操作2.6 测试 Thanks♪(・ω&#x…

申请便宜SSL证书 Let‘s Encrypt泛域名SSL证书

在当今数字化时代,网络安全已成为公众和企业关注的焦点。 申请Lets Encrypt便宜泛域名SSL证书步骤 1. 登录来此加密网站,输入域名,可以勾选泛域名和包含根域。 2. 选择加密方式,一般选择默认就可以了,也可以自定义CS…

【启明智显分享】乐鑫HMI方案2.8寸触摸串口屏应用于太阳能控制器

前言 太阳能作为一种无尽的、可再生的能源,在现代社会的能源结构中占据着日益重要的地位。而在太阳能应用系统中,有一种设备是不可或缺的,那就是太阳能控制器。太阳能控制器在太阳能系统中起着至关重要的作用,它保证系统的安全和…