当前位置: 首页 > news >正文

信号量(二值信号量和计数信号量)和互斥量

信号量

信号量(Semaphore) 是一种实现任务间通信的机制, 可以实现任务之间同步或临界资源的互斥访问, 常用于协助一组相互竞争的任务来访问临界资源。 在多任务系统中, 各任务之间需要同步或互斥实现临界资源的保护, 信号量功能可以为用户提供这方面的支持。

抽象的来讲, 信号量是一个非负整数, 所有获取它的任务都会将该整数减一(获取它当然是为了使用资源) , 当该整数值为零时, 所有试图获取它的任务都将处于阻塞状态。 通常一个信号量的计数值用于对应有效的资源数, 表示剩下的可被占用的互斥资源数。 其值的含义分两种情况:
●0: 表示没有积累下来的释放信号量操作, 且有可能有在此信号量上阻塞的任务。
●正值, 表示有一个或多个释放信号量操作。

 信号:起通知作用
 量:还可以用来表示资源的数量
 当"量"没有限制时,它就是"计数型信号量"(Counting Semaphores)
 当"量"只有 0、 1 两个取值时,它就是"二进制信号量"(Binary Semaphores)
 支持的动作: "give"给出资源,计数值加 1; "take"获得资源,计数值减 1

计数:事件产生时"give"信号量,让计数值加 1;处理事件时要先"take"信号量,就是获得信号量,让计数值减 1。
资源管理:要想访问资源需要先"take"信号量,让计数值减 1;用完资源后"give"信号量,让计数值加 1。

二值信号量

二值信号量既可以用于临界资源访问也可以用于同步功能。
二值信号量和互斥信号量(以下使用互斥量表示互斥信号量) 非常相似, 但是有一些细微差别: 互斥量有优先级继承机制, 二值信号量则没有这个机制。 这使得二值信号量更偏向应用于同步功能(任务与任务间的同步或任务和中断间同步) , 而互斥量更偏向应用于临界资源的访问。用作同步时, 信号量在创建后应被置为空, 任务 1 获取信号量而进入阻塞,任务 2 在某种条件发生后, 释放信号量, 于是任务 1 获得信号量得以进入就绪态, 如果任务 1 的优先级是最高的, 那么就会立即切换任务, 从而达到了两个任务间的同步。 同样的, 在中断服务函数中释放信号量, 任务 1 也会得到信号量, 从而达到任务与中断间的同步。

可以将二值信号量看作只有一个消息的队列, 因此这个队列只能为空或满(因此称为二值)我们在运用的时候只需要知道队列中是否有消息即可, 而无需关注消息是什么。

计数信号量

二进制信号量可以被认为是长度为 1 的队列, 而计数信号量则可以被认为长度大于 1 的队列, 信号量使用者依然不必关心存储在队列中的消息, 只需关心队列是否有消息即可。

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


 

信号量跟队列的对比


 

 常用信号量 API 函数

创建

使用信号量之前,要先创建,得到一个句柄;使用信号量时,要使用句柄来表明使用哪个信号量。


 

删除 

对于动态创建的信号量,不再需要它们时,可以删除它们以回收内存。
vSemaphoreDelete可以用来删除二进制信号量、计数型信号量

信号量释放函数 (give)

二进制信号量、计数型信号量的 give、 take 操作函数是一样的

 

 

 

 

 信号量获取函数 (take)

 

 

 

互斥量 

互斥量又称互斥信号量(本质是信号量) , 是一种特殊的二值信号量, 它和信号量不同的是, 它支持互斥量所有权、 递归访问以及防止优先级翻转的特性,用于实现对临界资源的独占式处理。

互斥量简介

互斥信号量其实就是一个拥有优先级继承的二值信号量, 在同步的应用中(任务与任务或中断与任务之间的同步)二值信号量最适合。 互斥信号量适合用于那些需要互斥访问的应用中。 在互斥访问中互斥信号量相当于一个钥匙, 当任务想要使用资源的时候就必须先获得这个钥匙, 当使用完资源以后就必须归还这个钥匙, 这样其他的任务就可以拿着这个钥匙去使用资源。

互斥信号量使用和二值信号量相同的 API 操作函数, 所以互斥信号量也可以设置阻塞时间, 不同于二值信号量的是互斥信号量具有优先级继承的特性。 当一个互斥信号量正在被一个低优先级的任务使用, 而此时有个高优先级的任务也尝试获取这个互斥信号量的话就会被阻塞。 不过这个高优先级的任务会将低优先级任务的优先级提升到与自己相同的优先级, 这个过程就是优先级继承。 优先级继承尽可能的降低了高优先级任务处于阻塞态的时间, 并且将已经出现的“优先级翻转” 的影响降到最低。

互斥量的优先级继承机制

在 FreeRTOS 操作系统中为了降低优先级翻转问题利用了优先级继承算法
优先级继承算法是指, 暂时提高某个占有某种资源的低优先级任务的优先级, 使之与在所有等待该资源的任务中优先级最高那个任务的优先级相等, 而当这个低优先级任务执行完毕释放该资源时, 优先级重新回到初始设定值。 因此, 继承优先级的任务避免了系统资源被任何中间优先级的任务抢占。

互斥量与二值信号量最大的不同是: 互斥量具有优先级继承机制, 而信号量没有。 也就是说, 某个临界资源受到一个互斥量保护, 如果这个资源正在被一个低优先级任务使用, 那么此时的互斥量是闭锁状态, 也代表了没有任务能申请到这个互斥量, 如果此时一个高优先级任务想要对这个资源进行访问, 去申请这个互斥量, 那么高优先级任务会因为申请不到互斥量而进入阻塞态, 那么系统会将现在持有该互斥量的任务的优先级临时提升到与高优先级任务的优先级相同, 这个优先级提升的过程叫做优先级继承。 这个优先级继承机制确保高优先级任务进入阻塞状态的时间尽可能短, 以及将已经出现的“优先级翻转” 危害降低到最小。

互斥量应用场景

互斥量的使用比较单一, 因为它是信号量的一种, 并且它是以锁的形式存在。
在初始化的时候, 互斥量处于开锁的状态, 而被任务持有的时候则立刻转为闭锁的状态。

互斥量更适合于
 ●可能会引起优先级翻转的情况。
递归互斥量更适用于:
●任务可能会多次获取互斥量的情况下。 这样可以避免同一任务多次递归持有而造成死锁的问题。 

多任务环境下往往存在多个任务竞争同一临界资源的应用场景, 互斥量可被用于对临界资源的保护从而实现独占式访问。 另外, 互斥量可以降低信号量存在的优先级翻转问题带来的影响。 

比如有两个任务需要对串口进行发送数据, 其硬件资源只有一个, 那么两个任务肯定不能同时发送啦, 不然导致数据错误, 那么, 就可以用互斥量对串口资源进行保护, 当一个任务正在使用串口的时候, 另一个任务则无法使用串口, 等到任务使用串口完毕之后, 另外一个任务才能获得串口的使用权。

另外需要注意的是互斥量不能在中断服务函数中使用, 因为其特有的优先级继承机制只在任务起作用, 在中断的上下文环境毫无意义。

常用API函数

互斥量创建函数

xSemaphoreCreateMutex()用于创建一个互斥量, 并返回一个互斥量句柄。

该句柄的原型是一个 void 型的指针, 在使用之前必须先由用户定义一个互斥量句柄。 要想使用该函数必须在 FreeRTOSConfig.h 中configSUPPORT_DYNAMIC_ALLOCATION 定义为 1, 即开启动态内存分配, 其实该宏在 FreeRTOS.h 中默认定义为 1, 即所有 FreeRTOS 的对象在创建的时候都默认使用动态内存分配方案, 同时还需在 FreeRTOSConfig.h 中把configUSE_MUTEXES 宏定义打开, 表示使用互斥量。

 

递归互斥量创建函数 

xSemaphoreCreateRecursiveMutex()用于创建一个递归互斥量, 不是递归的互斥量由函数 xSemaphoreCreateMutex() 或 xSemaphoreCreateMutexStatic()创建(我们只讲解动态创建) , 且只能被同一个任务获取一次, 如果同一个任务想再次获取则会失败。 递归信号量则相反, 它可以被同一个任务获取很多次, 获取多少次就需要释放多少次。 递归信号量与互斥量一样, 都实现了优先级继承机制, 可以降低优先级反转的危害。

要想使用该函数必须在 FreeRTOSConfig.h 中把宏configSUPPORT_DYNAMIC_ALLOCATION 和 configUSE_RECURSIVE_MUTEXES 均定义为 1。configSUPPORT_DYNAMIC_ALLOCATION 定义为 1 即表示开启动态内存分配, 其实该宏在 FreeRTOS.h 中默认定义为 1, 即所有 FreeRTOS 的对象在创建的时候都默认使用动态内存分配方案


 

互斥量删除函数 

互斥量的本质是信号量, 直接调用 vSemaphoreDelete()函数进行删除即可。

互斥量获取函数 

当互斥量处于开锁的状态, 任务才能获取互斥量成功, 当任务持有了某个互斥量的时候, 其它任务就无法获取这个互斥量, 需要等到持有互斥量的任务进行释放后, 其他任务才能获取成功, 任务通过互斥量获取函数来获取互斥量的所有权。 任务对互斥量的所有权是独占的, 任意时刻互斥量只能被一个任务持有, 如果互斥量处于开锁状态, 那么获取该互斥量的任务将成功获得该互斥
量, 并拥有互斥量的使用权; 如果互斥量处于闭锁状态, 获取该互斥量的任务将无法获得互斥量, 任务将被挂起, 在任务被挂起之前, 会进行优先级继承, 如果当前任务优先级比持有互斥量的任务优先级高, 那么将会临时提升持有互斥量任务的优先级。 互斥量的获取函数是一个宏定义, 实际调用的函数就是xQueueGenericReceive()。

递归互斥量获取函数

xSemaphoreTakeRecursive()是一个用于获取递归互斥量的宏, 与互斥量的获取函数一样, xSemaphoreTakeRecursive()也是一个宏定义, 它最终使用现有的队列机制, 实际执行的函数是 xQueueTakeMutexRecursive()。 互斥量之前必须由 xSemaphoreCreateRecursiveMutex()这个函数创建。 要注意的是该函数不能用于获取由函数 xSemaphoreCreateMutex()创建的互斥量。 要想使用该函数必须在头文件 FreeRTOSConfig.h 中把宏 configUSE_RECURSIVE_MUTEXES 定义为1。


 

互斥量释放函数 xSemaphoreGive()

任务想要访问某个资源的时候, 需要先获取互斥量, 然后进行资源访问, 在任务使用完该资源的时候, 必须要及时归还互斥量, 这样别的任务才能对资源进行访问

FreeRTOS 给我们提供了互斥量释放函数 xSemaphoreGive(), 任务可以调用 xSemaphoreGive()函数进行释放互斥量, 表示我已经用完了, 别人可以申请使用, 互斥量的释放函数与信号量的释
放函数一致, 都是调用 xSemaphoreGive()函数, 但是要注意的是, 互斥量的释放只能在任务中, 不允许在中断中释放互斥量。

使用该函数接口时, 只有已持有互斥量所有权的任务才能释放它, 当任务调用 xSemaphoreGive()函数时会将互斥量变为开锁状态, 等待获取该互斥量的任务将被唤醒。 如果任务的优先级被互斥量的优先级翻转机制临时提升, 那么当互斥量被释放后, 任务的优先级将恢复为原本设定的优先级


 

递归互斥量释放函数 xSemaphoreGiveRecursive() 

xSemaphoreGiveRecursive()是一个用于释放递归互斥量的宏。 要想使用该函数必须在头文件 FreeRTOSConfig.h 把宏 configUSE_RECURSIVE_MUTEXES 定义为 1。


 

xSemaphoreGiveRecursive()函数用于释放一个递归互斥量。 已经获取递归互斥量的任务可以重复获取该递归互斥量。 使用 xSemaphoreTakeRecursive()函数成功获取几次递归互斥量, 就要使用 xSemaphoreGiveRecursive()函数返还几次, 在此之前递归互斥量都处于无效状态, 别的任务就无法获取该递归互斥量。

使用该函数接口时, 只有已持有互斥量所有权的任务才能释放它, 每释放一次该递归互斥量, 它的计数值就减 1。 当该互斥量的计数值为 0 时(即持有任务已经释放所有的持有操作) , 互斥量则变为开锁状态, 等待在该互斥量上的任务将被唤醒。 如果任务的优先级被互斥量的优先级翻转机制临时提升, 那么当互斥量被释放后, 任务的优先级将恢复为原本设定的优先级。
 


 

 

 


 


 

相关文章:

信号量(二值信号量和计数信号量)和互斥量

信号量 信号量(Semaphore) 是一种实现任务间通信的机制, 可以实现任务之间同步或临界资源的互斥访问, 常用于协助一组相互竞争的任务来访问临界资源。 在多任务系统中, 各任务之间需要同步或互斥实现临界资源的保护&a…...

结构型模式-python版

在21种设计模式中, 结构型设计模式有7种, 分别是: 适配器模式代理模式桥接模式享元模式外观模式组合模式装饰器模式 下面逐一简要介绍: 1 适配器模式 适配器(Adapter)设计模式是一种结构型设计模式&…...

Java重修笔记 第五十四天 坦克大战(二)常用的绘图方法、画出坦克图形

常用的绘图方法 1.设置当前画笔的颜色,可多次调用 public abstract void setColor(Color c) 参数:c -颜色 2. 画一条直线 public abstract void drawLine(int x1, int y1, int x2, int y2) 参数:x1 - 第一个点的 x坐标。 y1 - 第一点的 y坐…...

OpenAI澄清:“GPT Next”不是新模型。

不,”GPT Next” 并不是OpenAI的下一个重要项目。 本周早些时候,OpenAI 日本业务的负责人长崎忠男在日本 KDDI 峰会上分享了一场演讲,似乎在暗示一个名为 “GPT Next” 的新模型即将出现。 但OpenAI的一位发言人已向Mashable证实&#xff0…...

<<编码>> 第 10 章 逻辑与开关(Logic and Switches) 示例电路

串联电路 info::操作说明 鼠标单击开关切换开合状态 需要两个开关同时闭合才能接通电路 primary::在线交互操作链接 https://cc.xiaogd.net/?startCircuitLinkhttps://book.xiaogd.net/code-hlchs-examples/assets/circuit/code-hlchs-ch10-01-series-circuit.txt 并联电路 in…...

深入浅出 Ansible 自动化运维:从入门到实战

在现代 IT 运维中,自动化是提升效率、降低错误率的关键。Ansible 作为一款流行的自动化工具,凭借其简洁的语法和强大的功能,成为了运维工程师的得力助手。本文将深入探讨 Ansible 的核心概念、实际应用以及一些实用的技巧,帮助你在…...

一句话描述设计模式

最近在看设计模式,其描述抽象程度令人欲罢不能,始终不得其意。于是尝试用一句话总结了一下,常规的就不说了,只是举了个例子。 单例模式 Spring中的单例bean使用了双重锁机制 工厂模式 Spring中的BeanFactory是简单工厂模式Bea…...

【Linux】Ubuntu 22.04 shell实现MySQL5.7 tar 一键安装

参考 https://blog.csdn.net/qq_35995514/article/details/134350572?spm1001.2014.3001.5501 在原作者基础上做了修改,加了一个删除原有mysql 的脚本 文章目录 一、安装下载**my.cnf 配置文件** 二、执行安装**install_mysql.sh 安装脚本**本机免密脚本 ssh_keyge…...

SQL Server开启网络访问

目前工作中很少用到SQL Server了,最近需要测试几个表,需要搭建一个SQL Server数据库服务,这里做个总结吧。 安装这里就不做详细介绍了,本文只介绍如何开启SQL Server网络访问。 1、云服务器安全组设置 如果是搭建在云服务器上&a…...

el-input设置type=‘number‘和v-model.number的区别

el-input设置typenumber’与设置.number修饰符的区别 1. 设置type‘number’ 使用el-input时想收集数字类型的数据,我们首先会想到typenumber,设置完type为number时会限制我们输入的内容只能为数字,不能为字符/汉字等非数字类型的数值&…...

6.第二阶段x86游戏实战2-理解程序流程

免责声明:内容仅供学习参考,请合法利用知识,禁止进行违法犯罪活动! 本次游戏没法给 内容参考于:微尘网络安全 工具下载: 链接:https://pan.baidu.com/s/1rEEJnt85npn7N38Ai0_F2Q?pwd6tw3 提…...

Netty笔记01-Netty的基本概念与用法

文章目录 1. 概述1.1 Netty 是什么?1.2 Netty 的特点1.3 Netty 的作者1.4 Netty 的地位1.5 Netty 的优势1.6 Netty 的工作原理1.7 Netty 的应用场景1.8 Netty 的重要组件 2. 第一个程序2.1 目标2.2 服务器端2.3 客户端2.4 流程梳理💡 提示 1. 概述 1.1 …...

OpenHarmony鸿蒙( Beta5.0)RTSPServer实现播放视频详解

鸿蒙开发往期必看: 一分钟了解”纯血版!鸿蒙HarmonyOS Next应用开发! “非常详细的” 鸿蒙HarmonyOS Next应用开发学习路线!(从零基础入门到精通) “一杯冰美式的时间” 了解鸿蒙HarmonyOS Next应用开发路…...

QT使用事件事件和绘制事件实现简易时钟

这个时钟实现的底层原理主要是利用 Qt 的绘图机制和定时器。首先,设置固定大小的窗口,创建定时器并连接到槽函数,定时器每秒钟触发一次,触发窗口重绘。在paintEvent函数中,使用QPainter进行绘图,绘制圆形表…...

kubeadm方式安装k8s

一、安装环境 环境准备:(有阿里云)centos7 k8s-master 192.168.1.11 k8s-node1 192.168.1.22 k8s-node2 192.168.1.33 二、前期准备 在k8s-master主机 [rootk8s-master ~]# vim /etc/hosts…...

如何使用go生成可执行文件

在 Go 中生成可执行文件非常简单。你可以使用 go build或者go install 命令。以下是步骤: 1. 步骤 1.1. 打开终端,导航到你的 Go 项目目录 确保你在包含 main 包的目录中,通常这是项目的根目录或包含 main.go 文件的目录。 1.2. 运行 go …...

手写Promise

构造器的实现 const PENDING pending; const FULFILLED fulfilled; const REJECTED rejectedclass MyPromise{#state PENDING;#result undefined;constructor(executor){const resolve (data) > {this.#changeState(FULFILLED, data);};const reject (reason) > …...

深度学习云服务器免费使用教程

#云服务器# #深度学习# #人工智能# #计算机视觉# 本文为各位学习深度学习的入门选手而创建,降低深度学习的入门门槛。 谷歌云服务器Colab: T4GPU。限额,需要科学上网,不能使用终端。 谷歌云服务器地址:欢迎使用 C…...

使用ansible的剧本制作salt-master与salt-minion的安装与启动服务过程

虚拟机版本:Rocky Linux release 8.6 (Green Obsidian) 准备几台虚拟机 ipv4地址主机名192.168.137.13center192.168.137.14sp-1192.168.137.15sp-2192.168.137.16sp-3 一、center主机的配置 1.vim /etc/hosts 127.0.0.1 localhost localhost.localdomain loc…...

数据库sqlite3

用数据库函数完成数据的增删改查 增: 将要存储的信息录入到结构体中,再使用snprintf函数信息结合sqlite3命令语句使用sqlite3_exec函数完成插入。 int do_insert(sqlite3 *ppDb) {Worker Work;printf("输入插入的工号:");scanf("%d&qu…...

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具,该工具基于TUN接口实现其功能,利用反向TCP/TLS连接建立一条隐蔽的通信信道,支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式,适应复杂网…...

黑马Mybatis

Mybatis 表现层&#xff1a;页面展示 业务层&#xff1a;逻辑处理 持久层&#xff1a;持久数据化保存 在这里插入图片描述 Mybatis快速入门 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/6501c2109c4442118ceb6014725e48e4.png //logback.xml <?xml ver…...

家政维修平台实战20:权限设计

目录 1 获取工人信息2 搭建工人入口3 权限判断总结 目前我们已经搭建好了基础的用户体系&#xff0c;主要是分成几个表&#xff0c;用户表我们是记录用户的基础信息&#xff0c;包括手机、昵称、头像。而工人和员工各有各的表。那么就有一个问题&#xff0c;不同的角色&#xf…...

智能在线客服平台:数字化时代企业连接用户的 AI 中枢

随着互联网技术的飞速发展&#xff0c;消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁&#xff0c;不仅优化了客户体验&#xff0c;还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用&#xff0c;并…...

EtherNet/IP转DeviceNet协议网关详解

一&#xff0c;设备主要功能 疆鸿智能JH-DVN-EIP本产品是自主研发的一款EtherNet/IP从站功能的通讯网关。该产品主要功能是连接DeviceNet总线和EtherNet/IP网络&#xff0c;本网关连接到EtherNet/IP总线中做为从站使用&#xff0c;连接到DeviceNet总线中做为从站使用。 在自动…...

uniapp中使用aixos 报错

问题&#xff1a; 在uniapp中使用aixos&#xff0c;运行后报如下错误&#xff1a; AxiosError: There is no suitable adapter to dispatch the request since : - adapter xhr is not supported by the environment - adapter http is not available in the build 解决方案&…...

Hive 存储格式深度解析:从 TextFile 到 ORC,如何选对数据存储方案?

在大数据处理领域&#xff0c;Hive 作为 Hadoop 生态中重要的数据仓库工具&#xff0c;其存储格式的选择直接影响数据存储成本、查询效率和计算资源消耗。面对 TextFile、SequenceFile、Parquet、RCFile、ORC 等多种存储格式&#xff0c;很多开发者常常陷入选择困境。本文将从底…...

C++.OpenGL (14/64)多光源(Multiple Lights)

多光源(Multiple Lights) 多光源渲染技术概览 #mermaid-svg-3L5e5gGn76TNh7Lq {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-3L5e5gGn76TNh7Lq .error-icon{fill:#552222;}#mermaid-svg-3L5e5gGn76TNh7Lq .erro…...

初探Service服务发现机制

1.Service简介 Service是将运行在一组Pod上的应用程序发布为网络服务的抽象方法。 主要功能&#xff1a;服务发现和负载均衡。 Service类型的包括ClusterIP类型、NodePort类型、LoadBalancer类型、ExternalName类型 2.Endpoints简介 Endpoints是一种Kubernetes资源&#xf…...

SQL慢可能是触发了ring buffer

简介 最近在进行 postgresql 性能排查的时候,发现 PG 在某一个时间并行执行的 SQL 变得特别慢。最后通过监控监观察到并行发起得时间 buffers_alloc 就急速上升,且低水位伴随在整个慢 SQL,一直是 buferIO 的等待事件,此时也没有其他会话的争抢。SQL 虽然不是高效 SQL ,但…...