(学习日记)2024.04.05:UCOSIII第三十三节:互斥量

写在前面:
由于时间的不足与学习的碎片化,写博客变得有些奢侈。
但是对于记录学习(忘了以后能快速复习)的渴望一天天变得强烈。
既然如此
不如以天为单位,以时间为顺序,仅仅将博客当做一个知识学习的目录,记录笔者认为最通俗、最有帮助的资料,并尽量总结几句话指明本质,以便于日后搜索起来更加容易。


标题的结构如下:“类型”:“知识点”——“简短的解释”
部分内容由于保密协议无法上传。


点击此处进入学习日记的总目录

2024.04.05:UCOSIII第三十一节:互斥量

  • 四十七、UCOSIII:互斥量
    • 1、互斥量的基本概念
    • 2、互斥量的优先级继承机制
      • 1. 优先级翻转
      • 2. 优先级继承
    • 3、互斥量应用场景
    • 4、互斥量运作机制
    • 5、互斥量控制块

四十七、UCOSIII:互斥量

1、互斥量的基本概念

互斥量又称互斥信号量(本质也是一种信号量,不具备传递数据功能),是一种特殊的二值信号量,它和信号量不同的是, 它支持互斥量所有权、递归访问以及防止优先级翻转的特性,用于实现对临界资源的独占式处理。
任意时刻互斥量的状态只有两种, 开锁或闭锁。当互斥量被任务持有时,该互斥量处于闭锁状态,这个任务获得互斥量的所有权。
当该任务释放这个互斥量时, 该互斥量处于开锁状态,任务失去该互斥量的所有权。
当一个任务持有互斥量时,其他任务将不能再对该互斥量进行开锁或持有。
持有该互斥量的任务也能够再次获得这个锁而不被挂起,这就是递归访问,也就是递归互斥量的特性,这个特性与一般的信号量有很大的不同, 在信号量中,由于已经不存在可用的信号量,任务递归获取信号量时会发生主动挂起任务最终形成死锁。

如果想要用于实现同步(任务之间或者任务与中断之间),二值信号量或许是更好的选择,虽然互斥量也可以用于任务与任务间同步, 但是互斥量更多的是用于保护资源的互锁。

用于互锁的互斥量可以充当保护资源的令牌,当一个任务希望访问某个资源时,它必须先获取令牌。
当任务使用完资源后,必须还回令牌, 以便其他任务可以访问该资源。是不是很熟悉,在我们的二值信号量里面也是一样的,用于保护临界资源,保证多任务的访问井然有序。
当任务获取到信号量的时候才能开始使用被保护的资源,使用完就释放信号量,下一个任务才能获取到信号量从而可用使用被保护的资源。
但是信号量会导致的另一个潜在问题,那就是任务优先级翻转(具体会在下文讲解)。
而μC/OS提供的互斥量可以通过优先级继承算法, 可以降低优先级翻转问题产生的影响,所以,用于临界资源的保护一般建议使用互斥量。

2、互斥量的优先级继承机制

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

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

没有理解?没问题,结合过程示意图再说一遍。

1. 优先级翻转

我们知道任务的优先级在创建的时候就已经是设置好的,高优先级的任务可以打断低优先级的任务, 抢占CPU的使用权。
但是在很多场合中,某些资源只有一个,当低优先级任务正在占用该资源的时候, 即便高优先级任务也只能乖乖的等待低优先级任务使用完该资源后释放资源。
这里高优先级任务无法运行而低优先级任务可以运行的现象称为“优先级翻转”。

为什么说优先级翻转在操作系统中是危害很大?
因为在我们一开始创造这个系统的时候,我们就已经设置好了任务的优先级了,越重要的任务优先级越高。
但是发生优先级翻转,对我们操作系统是致命的危害,会导致系统的高优先级任务阻塞时间过长。

举个例子,现在有3个任务分别为H任务(High)、M任务(Middle)、L任务(Low),3个任务的优先级顺序为H任务>M任务>L任务。
正常运行的时候H任务可以打断M任务与L任务,M任务可以打断L任务,假设系统中有一个资源被保护了,此时该资源被L任务正在使用中, 某一刻,H任务需要使用该资源,但是L任务还没使用完,H任务则因为申请不到资源而进入阻塞态,L任务继续使用该资源,此时已经出现了“优先级翻转”现象, 高优先级任务在等着低优先级的任务执行。
如果在L任务执行的时候刚好M任务被唤醒了,由于M任务优先级比L任务优先级高,那么会打断L任务, 抢占了CPU的使用权,直到M任务执行完,再把CPU使用权归还给L任务,L任务继续执行,等到执行完毕之后释放该资源,H任务此时才从阻塞态解除, 使用该资源。
这个过程,本来是最高优先级的H任务,在等待了更低优先级的L任务与M任务,其阻塞的时间是M任务运行时间+L任务运行时间, 这只是只有3个任务的系统,假如很多个这样子的任务打断最低优先级的任务,那这个系统最高优先级任务岂不是崩溃了,这个现象是绝对不允许出现的, 高优先级的任务必须能及时响应。
所以,没有优先级继承的情况下,使用资源保护,其危害极大,具体见图
在这里插入图片描述

  • (1):L任务正在使用某临界资源, H任务被唤醒,执行H任务。但L任务并未执行完毕,此时临界资源还未释放。
  • (2):这个时刻H任务也要对该临界资源进行访问, 但 L任务还未释放资源,由于保护机制,H任务进入阻塞态,L任务得以继续运行,此时已经发生了优先级翻转现象。
  • (3):某个时刻M任务被唤醒,由于M任务的优先级高于L任务, M任务抢占了CPU的使用权,M任务开始运行,此时L任务尚未执行完,临界资源还没被释放。
  • (4):M任务运行结束,归还CPU使用权,L任务继续运行。
  • (5):L任务运行结束,释放临界资源,H任务得以对资源进行访问,H任务开始运行。

在这过程中,H任务的等待时间过长,这对系统来说这是很致命的。
所以这种情况不允许出现,而互斥量就是用来降低优先级翻转的产生的危害。

2. 优先级继承

假如有优先级继承呢?
那么,在H任务申请该资源的时候,由于申请不到资源会进入阻塞态,那么系统就会把当前正在使用资源的L任务的优先级临时提高到与H任务优先级相同, 此时M任务被唤醒了,因为它的优先级比H任务低,所以无法打断L任务,因为此时L任务的优先级被临时提升到H,所以当L任务使用完该资源了,进行释放, 那么此时H任务优先级最高,将接着抢占CPU的使用权, H任务的阻塞时间仅仅是L任务的执行时间,此时的优先级的危害降到了最低。具体见图
在这里插入图片描述

  • (1):L任务正在使用某临界资源,L任务正在使用某临界资源, H任务被唤醒,执行H任务。但L任务并未执行完毕,此时临界资源还未释放。
  • (2):某一时刻H任务也要对该资源进行访问,由于保护机制, H任务进入阻塞态。此时发生优先级继承,系统将L任务的优先级暂时提升到与H任务优先级相同,L任务继续执行。
  • (3):在某一时刻M任务被唤醒,由于此时M任务的优先级暂时低于L任务,所以M任务仅在就绪态,而无法获得CPU使用权。
  • (4):L任务运行完毕,H任务获得对资源的访问权,H任务从阻塞态变成运行态,此时L任务的优先级会变回原来的优先级。
  • (5):当H任务运行完毕,M任务得到CPU使用权,开始执行。
  • (6):系统正常运行,按照设定好的优先级运行。

但是使用互斥量的时候一定需要注意:
在获得互斥量后,请尽快释放互斥量,同时需要注意的是在任务持有互斥量的这段时间, 不得更改任务的优先级。
ΜC/OS的优先级继承机制不能解决优先级翻转,只能将这种情况的影响降低到最小,硬实时系统在一开始设计时就要避免优先级翻转发生。

3、互斥量应用场景

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

互斥量更适合于:

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

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

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

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

4、互斥量运作机制

多任务环境下会存在多个任务访问同一临界资源的场景,该资源会被任务独占处理。
其他任务在资源被占用的情况下不允许对该临界资源进行访问, 这个时候就需要用到μC/OS的互斥量来进行资源保护,那么互斥量是怎样来避免这种冲突?

用互斥量处理不同任务对临界资源的同步访问时,任务想要获得互斥量才能进行资源访问。
如果一旦有任务成功获得了互斥量,则互斥量立即变为闭锁状态。
此时其他任务会因为获取不到互斥量而不能访问这个资源,任务会根据用户自定义的等待时间进行等待,直到互斥量被持有的任务释放后, 其他任务才能获取互斥量从而得以访问该临界资源。
此时互斥量再次上锁,如此一来就可以确保每个时刻只有一个任务正在访问这个临界资源,保证了临界资源操作的安全性。
在这里插入图片描述

  • (1):因为互斥量具有优先级继承机制,一般选择使用互斥量对资源进行保护, 如果资源被占用的时候,无论是什么优先级的任务想要使用该资源都会被阻塞。
  • (2):假如正在使用该资源的任务1比阻塞中的任务2的优先级还低, 那么任务1将被系统临时提升到与高优先级任务2相等的优先级(任务1的优先级从L 变成H)。
  • (3):当任务1使用完资源之后,释放互斥量,此时任务1的优先级会从H变回原来的L。
  • (4)-(5):任务2此时可以获得互斥量,然后进行资源的访问, 当任务2访问了资源的时候,该互斥量的状态又为闭锁状态,其他任务无法获取互斥量。

5、互斥量控制块

μC/OS的互斥量由多个元素组成,在互斥量被创建时,需要由我们自己定义互斥量(也可以称之为互斥量句柄)。
因为它是用于保存互斥量的一些信息的, 其数据结构OS_MUTEX除了互斥量必须的一些基本信息外,还有指向任务控制块的指针OwnerTCBPtr、任务优先级变量OwnerOriginalPrio、 PendList链表与OwnerNestingCtr变量等,为的是方便系统来管理互斥量。
示意图具体见图:
在这里插入图片描述

其数据结构具体如何:

struct  os_mutex{
/* ------------------ GENERIC  MEMBERS ------------------ */OS_OBJ_TYPE          Type;                 (1)CPU_CHAR            *NamePtr;              (2)OS_PEND_LIST         PendList;             (3)#if OS_CFG_DBG_EN > 0uOS_MUTEX            *DbgPrevPtr;OS_MUTEX            *DbgNextPtr;CPU_CHAR            *DbgNamePtr;
#endif
/* ------------------ SPECIFIC MEMBERS ------------------ */OS_TCB              *OwnerTCBPtr;               (4)OS_PRIO              OwnerOriginalPrio; (5)OS_NESTING_CTR       OwnerNestingCtr;       (6)CPU_TS               TS;                        (7)
};
  • (1):互斥量的类型,用户无需理会,μC/OS能识别它是一个mutex。
  • (2):互斥量的名字,每个内核对象都被分配一个名。
  • (3):等待互斥量的任务列表。
  • (4):指向持有互斥量任务控制块的指针, 如果任务占用这个mutex,那么该变量OwnerTCBPtr会指向占用这个mutex的任务的OS_TCB。
  • (5):用于记录持有互斥量任务的优先级, 如果任务占用这个mutex,那么该变量OwnerOriginalPrio中存放着任务的原优先级,当占用mutex任务的优先级被提升时就会用到这个变量。
  • (6):表示互斥量是否可用,当该值为0的时候表示互斥量处于开锁状态, 互斥量可用。μC/OS允许任务递归调用同一个mutex多达256次,每递归调用一次mutex该值就会加一,但也需要释放相同次数才能真正释放掉这个mutex。
  • (7):mutex中的变量TS用于保存该mutex最后一次被释放的时间戳。 当mutex被释放,读取时基计数值并存放到该变量中。

注意:
用户代码不能直接访问这个结构体,必须通过μC/OS提供的API访问。

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

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

相关文章

51单片机入门_江协科技_17~18_OB记录的笔记

17. 定时器 17.1. 定时器介绍:51单片机的定时器属于单片机的内部资源,其电路的连接和运转均在单片机内部完成,无需占用CPU外围IO接口; 定时器作用: (1)用于计时系统,可实现软件计时&…

C语言题目:分段函数练习

题目描述 输入x ,计算并输出下列分段函数 f(x) 的值。可以调用数学库函数:平方根函数sqrt(),绝对值函数fabs() 和幂函数 pow()。 保留2位小数 输入格式 x 输出格式 f(x) 样例输入 5 样例输出 15.00 代码分析 包含标准输入输出库和数学库: #incl…

Linux -- 字符设备驱动--LED的驱动开发(初级框架)

驱动框架一阶段 我们怎样去点亮一个 LED 呢?分为三步: 看原理图确定引脚,确定引脚输出什么电平才能点亮/熄灭 LED 看主芯片手册,确定寄存器操作方法:哪些寄存器?哪些位?地址是? 编…

webpack5如何关闭全屏错误

1、找到vue.config.js 2、在上面的devServer里面添加如下: client: {overlay: false, // 禁用全局错误提示},

mynet开源库

1.介绍 个人实现的c开源网络库. 2.软件架构 1.结构图 2.基于event的自动分发机制 3.多优先级分发队列,延迟分发队列 内部event服务于通知机制的优先级为0,外部event优先级为1. 当集中处理分发的event_callback时&#xff0c…

更新!谷歌倾斜摄影转换生成OSGB瓦片V0.2版

半个月前发表了一篇文章(首发!谷歌倾斜摄影转换生成OSGB格式),首次将谷歌原始倾斜摄影瓦片转成OSGB瓦片,有读者对文章里的内容有诸多疑问,可能我在文章中描述的不够清楚,这里再解释一下。 1.谷歌倾斜摄影3DTiles瓦片生成方案 之…

若依ts版本(vue3+element plus+ts)

1、项目简介 本项目参考若依前后端分离版,前端由[若依vue3]改写为ts版本[ruoyi-web-vue3-ts],后端对[若依V3.8.7]进行了修改[后端版本分支vue3.ts.3.8.7],具体文档参见[若依官方文档]。本项目对部分代码做了优化,增加了activiti7…

langchain 学习笔记-FunctionCalling三种方式

ChatGPT 基于海量的训练数据生成答案,所以它无法回答训练数据中没有的信息或搜索信息 。人们希望 ChatGPT 具有对话以外的各种功能,例如“我想管理我的待办事项列表”。 函数调用是对此类请求的响应。 通过使用函数调用,ChatGPT 现在可以在生…

Vue-ts项目导入Js文件方法-书写提示无法找到模块“XXXX”的声明文件-配置说明

提示 无法找到模块“/filter/filter”的声明文件。“d:/code/byWork/mixmarvel/SendAssetsClient/src/filter/filter.js”隐式拥有 "any" 类型。 解决方法 修改 tsconfig.json {"compilerOptions": {"target": "esnext","modu…

RIP配置不求人:手把手教你配置RIP路由

#教育优质作者发文挑战赛# 大家好,今天给同学们介绍一下RIP基本功能相关配置 01、基本概念 RIP是一种基于距离矢量(Distance-Vector)算法的协议,它使用跳数(Hop Count)作为度量值来衡量到达目的地址的距离…

耐压40V、输出电压1.23-37V可调,适用于工控主板、TV板卡、安卓主板、车载功放电源等产品方案应用。

一、应用领域 适用于工控主板、TV板卡、安卓主板、车载功放电源等产品方案应用。 二、功能介绍 D1509是一款输入耐压40V、输出电压1.23-37V可调、输出电流最大2.0A的高效率、高精度DC-DC芯片,其输出电压有固定3.3V、5.0V和12.0V的版本,可以为客户省去…

【2024】Rancher的安装与介绍

———————————————————————————— 记录一下rancher的学习与使用过程 本部分内容包括rancher的介绍、特点、与k8s关系和部署等内容 ———————————————————————————— Rancher是什么? 简单来说,Ranc…

BIDI的单芯双向光模块是在用哪里的?

为什么要选择BIDI光模块? BIDI光学模块最明显的优点,如SFP BIDI光学模块或SFP BIDI光学模块,可以减少光纤跳线面板上的端口数量,节省光纤布线基础设施的成本,减少布线空间,方便光纤的管理,减少…

什么是电子邮件加密?电子邮件加密有几种类型?

在当今数字时代,电子邮件已经成为人们日常生活中不可或缺的沟通工具,据相关数据统计,全球每天发送的电子邮件数以亿计,而这些邮件里面通常包含了姓名、地址、个人身份信息 (PII)、登录凭证、财务信息、法律合同、知识产权等有价值…

ssh: Could not resolve hostname xxx: Name or service not known

参考文章:https://blog.csdn.net/bewhyw/article/details/134452826 修改etc/hosts中的文件,加入所有主机的地址映射即可: vi /etc/hosts

AI智慧医疗:探索机器学习在医疗保健中的应用与进展

🧑 作者简介:阿里巴巴嵌入式技术专家,深耕嵌入式人工智能领域,具备多年的嵌入式硬件产品研发管理经验。 📒 博客介绍:分享嵌入式开发领域的相关知识、经验、思考和感悟,欢迎关注。提供嵌入式方向的学习指导…

【漏洞预警】Linux kernel权限提升漏洞(CVE-2024-1086)

一、漏洞概述 漏洞名称 Linux kernel权限提升漏洞 CVE ID CVE-2024-1086 漏洞类型 Use-After-Free 发现时间 2024-03-28 漏洞评分 7.8 漏洞等级 高危 攻击向量 本地 所需权限 低 利用难度 低 用户交互 无 PoC/EXP 已公开 在野利用 未知 Netfilte…

静态数码管

文章目录 前言一、静态数码管原理二、静态数码管显示1.单个数码管 奇数偶数2.显示任意四位数 0000-9999 总结 前言 提示:这里可以添加本文要记录的大概内容: 课程需要: 提示:以下是本篇文章正文内容,下面案例可供参考…

DFMEA的输入与输出——SunFMEA软件

DFMEA泛应用于产品设计阶段,以识别潜在的失效模式,评估其对系统的影响,并制定相应的预防措施。DFMEA的输入与输出是这一过程中至关重要的两个环节,它们直接决定了分析的质量与效果。今天SunFMEA软件系统和大家一起分享DFMEA的输入…

飞书API(3):Python 自动读取多维表所有分页数据的三种方法

上一小节介绍了怎么使用 Python 读取多维表的数据,看似可以成功获取到了所有的数据,但是在实际生产使用过程中,我们会发现,上一小节的代码并不能获取到所有的多维表数据,它只能获取一页,默认是第一页。因为…