RT-Thread 互斥量的概念
目录
概述
1 互斥量定义
1.1 概念介绍
1.2 线程优先级翻转问题
2 互斥量管理
2.1 结构体定义
2.2 函数接口介绍
2.2.1 rt_mutex_create函数
2.2.2 rt_mutex_delete 函数
2.2.3 初始化和脱离互斥量
概述
本文主要介绍互斥量的概念,实现原理。还介绍RT-Thread中互斥量的相关接口。
1 互斥量定义
1.1 概念介绍
互斥量又叫相互排斥的信号量,是一种特殊的二值信号量。互斥量类似于只有一个车位的停车场:当有一辆车进入的时候,将停车场大门锁住,其他车辆在外面等候。当里面的车出来时,将停车场大门打开,下一辆车才可以进入。
互斥量和信号量不同的是:拥有互斥量的线程拥有互斥量的所有权,互斥量支持递归访问且能防止线程优先级翻转;并且互斥量只能由持有线程释放,而信号量则可以由任何线程释放。
互斥量的状态只有两种,开锁或闭锁(两种状态值)。
当有线程持有它时,互斥量处于闭锁状态,由这个线程获得它的所有权。
相反,当这个线程释放它时,将对互斥量进行开锁,失去它的所有权。
当一个线程持有互斥量时,其他线程将不能够对它进行开锁或持有它,持有该互斥量的线程也能够再次获得这个锁而不被挂起,如下图时所示。这个特性与一般的二值信号量有很大的不同:在信号量中,因为已经不存在实例,线程递归持有会发生主动挂起(最终形成死锁)。
1.2 线程优先级翻转问题
使用信号量会导致的另一个潜在问题是线程优先级翻转问题。
所谓优先级翻转,即当一个高优先级线程试图通过信号量机制访问共享资源时,如果该信号量已被一低优先级线程持有,而这个低优先级线程在运行过程中可能又被其它一些中等优先级的线程抢占,因此造成高优先级线程被许多具有较低优先级的线程阻塞,实时性难以得到保证。
如下图所示:有优先级为 A、B 和 C 的三个线程,优先级 A> B > C。
step -1: 线程 A,B 处于挂起状态,等待某一事件触发,线程 C 正在运行,此时线程 C 开始使用某一共享资源 M。
step-2: 在使用过程中,线程 A 等待的事件到来,线程 A 转为就绪态,因为它比线程 C 优先级高,所以立即执行。
step-3: 但是当线程 A 要使用共享资源 M 时,由于其正在被线程 C 使用,因此线程 A 被挂起切换到线程 C 运行。
step-4: 如果此时线程 B 等待的事件到来,则线程 B 转为就绪态。由于线程 B 的优先级比线程 C 高,且线程B没有用到共享资源 M ,因此线程 B 开始运行,直到其运行完毕,线程 C 才开始运行。
只有当线程 C 释放共享资源 M 后,线程 A 才得以执行。在这种情况下,优先级发生了翻转:线程 B 先于线程 A 运行。这样便不能保证高优先级线程的响应时间。
在 RT-Thread 操作系统中,互斥量可以解决优先级翻转问题,实现的是优先级继承协议 (Sha, 1990)。优先级继承是通过在线程 A 尝试获取共享资源而被挂起的期间内,将线程 C 的优先级提升到线程 A 的优先级别,从而解决优先级翻转引起的问题。这样能够防止 C(间接地防止 A)被 B 抢占,如下图所示。优先级继承是指,提高某个占有某种资源的低优先级线程的优先级,使之与所有等待该资源的线程中优先级最高的那个线程的优先级相等,然后执行,而当这个低优先级线程释放该资源时,优先级重新回到初始设定。因此,继承优先级的线程避免了系统资源被任何中间优先级的线程抢占。
2 互斥量管理
2.1 结构体定义
在 RT-Thread 中,互斥量控制块是操作系统用于管理互斥量的一个数据结构,由结构体 struct rt_mutex 表示。另外一种 C 表达方式 rt_mutex_t,表示的是互斥量的句柄,在 C 语言中的实现是指互斥量控制块的指针。互斥量控制块结构的详细定义请见以下代码:
struct rt_mutex{struct rt_ipc_object parent; /* 继承自 ipc_object 类 */
rt_uint16_t value; /* 互斥量的值 */rt_uint8_t original_priority; /* 持有线程的原始优先级 */rt_uint8_t hold; /* 持有线程的持有次数 */struct rt_thread *owner; /* 当前拥有互斥量的线程 */};/* rt_mutext_t 为指向互斥量结构体的指针类型 */typedef struct rt_mutex* rt_mutex_t;
rt_mutex 对象从 rt_ipc_object 中派生,由 IPC 容器所管理。
2.2 函数接口介绍
互斥量控制块中含有互斥相关的重要参数,在互斥量功能的实现中起到重要的作用。互斥量相关接口如下图所示,对一个互斥量的操作包含:创建 / 初始化互斥量、获取互斥量、释放互斥量、删除 / 脱离互斥量。
2.2.1 rt_mutex_create函数
创建一个互斥量时,内核首先创建一个互斥量控制块,然后完成对该控制块的初始化工作。创建互斥量使用下面的函数接口:
rt_mutex_t rt_mutex_create (const char* name, rt_uint8_t flag);
可以调用 rt_mutex_create 函数创建一个互斥量,它的名字由 name 所指定。当调用这个函数时,系统将先从对象管理器中分配一个 mutex 对象,并初始化这个对象,然后初始化父类 IPC 对象以及与 mutex 相关的部分。互斥量的 flag 标志已经作废,无论用户选择 RT_IPC_FLAG_PRIO 还是 RT_IPC_FLAG_FIFO,内核均按照 RT_IPC_FLAG_PRIO 处理。下表描述了该函数的输入参数与返回值:
参数 | 描述 |
---|---|
name | 互斥量的名称 |
flag | 该标志已经作废,无论用户选择 RT_IPC_FLAG_PRIO 还是 RT_IPC_FLAG_FIFO,内核均按照 RT_IPC_FLAG_PRIO 处理 |
返回 | —— |
互斥量句柄 | 创建成功 |
RT_NULL | 创建失败 |
2.2.2 rt_mutex_delete 函数
当不再使用互斥量时,通过删除互斥量以释放系统资源,适用于动态创建的互斥量。删除互斥量使用下面的函数接口:
rt_err_t rt_mutex_delete (rt_mutex_t mutex);
当删除一个互斥量时,所有等待此互斥量的线程都将被唤醒,等待线程获得的返回值是 - RT_ERROR。然后系统将该互斥量从内核对象管理器链表中删除并释放互斥量占用的内存空间。下表描述了该函数的输入参数与返回值:
参数 | 描述 |
---|---|
mutex | 互斥量对象的句柄 |
返回 | —— |
RT_EOK | 删除成功 |
2.2.3 初始化和脱离互斥量
静态互斥量对象的内存是在系统编译时由编译器分配的,一般放于读写数据段或未初始化数据段中。在使用这类静态互斥量对象前,需要先进行初始化。初始化互斥量使用下面的函数接口:
rt_err_t rt_mutex_init (rt_mutex_t mutex, const char* name, rt_uint8_t flag);
使用该函数接口时,需指定互斥量对象的句柄(即指向互斥量控制块的指针),互斥量名称以及互斥量标志。互斥量标志可用上面创建互斥量函数里提到的标志。下表描述了该函数的输入参数与返回值:
参数 | 描述 |
---|---|
mutex | 互斥量对象的句柄,它由用户提供,并指向互斥量对象的内存块 |
name | 互斥量的名称 |
flag | 该标志已经作废,无论用户选择 RT_IPC_FLAG_PRIO 还是 RT_IPC_FLAG_FIFO,内核均按照 RT_IPC_FLAG_PRIO 处理 |
返回 | —— |
RT_EOK | 初始化成功 |
脱离互斥量将把互斥量对象从内核对象管理器中脱离,适用于静态初始化的互斥量。脱离互斥量使用下面的函数接口:
rt_err_t rt_mutex_detach (rt_mutex_t mutex);
使用该函数接口后,内核先唤醒所有挂在该互斥量上的线程(线程的返回值是 -RT_ERROR),然后系统将该互斥量从内核对象管理器中脱离。下表描述了该函数的输入参数与返回值:
参数 | 描述 |
---|---|
mutex | 互斥量对象的句柄 |
返回 | —— |
RT_EOK | 成功 |
相关文章:

RT-Thread 互斥量的概念
目录 概述 1 互斥量定义 1.1 概念介绍 1.2 线程优先级翻转问题 2 互斥量管理 2.1 结构体定义 2.2 函数接口介绍 2.2.1 rt_mutex_create函数 2.2.2 rt_mutex_delete 函数 2.2.3 初始化和脱离互斥量 概述 本文主要介绍互斥量的概念,实现原理。还介绍RT-Thre…...

6.计算机网络_UDP
UDP的主要特点: 无连接,发送数据之前不需要建立连接。不保证可靠交付。面向报文。应用层给UDP报文后,UDP并不会抽象为一个一个的字节,而是整个报文一起发送。没有拥塞控制。网络拥堵时,发送端并不会降低发送速率。可以…...

Windows应急响蓝安服面试
Windows应急响应 蓝队溯源流程 学习Windows应急首先要站在攻击者的角度去学习一些权限维持和权限提升的方法.,文章中的方法其实和内网攻防笔记有类似l红队教你怎么利用 蓝队教你怎么排查 攻防一体,应急响应排查这些项目就可以 端口/服务/进程/后门文件都是为了权限维持,得到s…...

PCL 点云配准-4PCS算法(粗配准)
目录 一、概述 1.1原理 1.2实现步骤 1.3应用场景 二、代码实现 2.1关键函数 2.1.1 加载点云数据 2.1.2 执行4PCS粗配准 2.1.3 可视化源点云、目标点云和配准结果 2.2完整代码 三、实现效果 3.1原始点云 3.2配准后点云 PCL点云算法汇总及实战案例汇总的目录地址链接…...

12、论文阅读:利用生成对抗网络实现无监督深度图像增强
Towards Unsupervised Deep Image Enhancement With Generative Adversarial Network 摘要介绍相关工作传统图像增强基于学习的图像增强 论文中提出的方法动机和目标网络架构损失函数1) 质量损失2) 保真损失3)身份损失4)Total Loss 实验 摘要 提高图像的…...

Axure重要元件三——中继器表单制作
亲爱的小伙伴,在您浏览之前,烦请关注一下,在此深表感谢! 本节课:中继器表单制作 课程内容:利用中继器制作表单 应用场景:台账、表单 案例展示: 步骤一:建立一个背景区…...

DMAIC赋能智能家居:解锁未来生活新篇章!
从清晨自动拉开的窗帘,到夜晚自动调暗的灯光,每一处细节都透露着科技的温度与智慧的光芒。而在这场智能革命的浪潮中,DMAIC(定义Define、测量Measure、分析Analyze、改进Improve、控制Control)作为六西格玛管理的核心方…...
代码随想录算法训练营第二天| 209.长度最小的子数组 59.螺旋矩阵II 区间和 开发商购买土地
209. 长度最小的子数组 题目: 给定一个包含正整数的数组 nums 和一个正整数 target ,找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 ,并返回其长度。如果不存在符合条件的子数组,返回 0。 示例: 示例 1…...
mysql隐藏索引
1. 什么是隐藏索引? 在 MySQL 8 中,隐藏索引(Invisible Indexes)是指一种特殊类型的索引,它并不真正被删除,而是被标记为“不可见”。当索引被标记为不可见时,查询优化器在生成查询计划时将忽略…...
etcd入门到实战
概述:本文将介绍etcd特性、使用场景、基本原理以及Linux环境下的实战操作 入门 什么是etcd? etcd是一个分布式键值存储数据库 关键字解析: 键值存储:存储协议是 key—value 的形式,类似于redis分布式:…...
Build an Android project and get a `.apk` file on a Debian 11 command line
You can build an Android project and get a .apk file on a Debian 11 command line without using Android Studio. The process involves using the Android SDK command-line tools (sdkmanager, adb, and gradle). Here’s a step-by-step guide to building the ???…...
解读 Java 经典巨著《Effective Java》90条编程法则,第4条:通过私有构造器强化不可实例化的能力
文章目录 【前言】欢迎订阅【解读《Effective Java》】系列专栏java.lang.Math 类的设计经验总结 【前言】欢迎订阅【解读《Effective Java》】系列专栏 《Effective Java》是 Java 开发领域的经典著作,作者 Joshua Bloch 以丰富的经验和深入的知识,全面…...

Vivado HLS学习
视频链接: 6课:数据类型的转换_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1bt41187RW?spm_id_from333.788.videopod.episodes&vd_sourcea75d5585c5297210add71187236ec90b&p6 目录 1.数据类型的转换 2.自动类型转换 2.1隐式数据转换 2.2…...

一款AutoXJS现代化美观的日志模块AxpLogger
简介 Axp Logger是一款基于autox.js的现代化日志模块,具备窗口事件穿透、拖拽和缩放功能。 Axp Logger文档 特性现代化的UI设计支持点击穿透模式(不影响脚本运行)监听音量-键切换模式支持窗口操作模式窗口拖拽移动窗口自由缩放清空日志关闭日…...

成都睿明智科技有限公司共创抖音电商新篇章
在当今这个数字化浪潮汹涌的时代,抖音电商以其独特的魅力迅速崛起,成为众多商家竞相追逐的新蓝海。在这片充满机遇与挑战的领域中,成都睿明智科技有限公司凭借其专业的服务、创新的策略和敏锐的市场洞察力,成为了众多商家信赖的合…...

Spark的安装配置及集群搭建
Spark的本地安装配置: 我们用scala语言编写和操作spark,所以先要完成scala的环境配置 1、先完成Scala的环境搭建 下载Scala插件,创建一个Maven项目,导入Scala依赖和插件 scala依赖 <dependency><groupId>org.scal…...

网络编程基础-IO模型深入理解
一、IO的基本概念 什么是IO? I/O就是计算机内存与外部设备之间拷贝数据的过程 什么是网络IO? 网络IO是指在计算机网络环境中进行的输入和输出操作,涉及数据在网络设备之间的传输。 网络IO操作可以是发送请求、接收响应、下载文件、传输数…...

go 语言学习路线图(一)
1. Go语言简介 Go语言的历史背景和设计理念Go的优势:简洁、高效、并发支持强Go的应用场景:微服务、云计算、系统编程 2. 开发环境设置 安装Go语言开发环境 在Windows、macOS、Linux系统上的安装方法 配置环境变量:GOROOT 和 GOPATH验证安装…...

前端自动化部署,Netlify免费满足你
1 Netlify 介绍 为什么推荐 Netliy , 主要还是穷,Netlify 免费太香了 Netlify you优势100GB 内免费 ,满足个人日常 需求,操作,兼容性绑定代码仓库,提交代码自动部署 支持 github , gitlab 等 大多常用代码仓库易操作只…...

Linux的开发工具gcc Makefile gdb的学习
一:gcc/g 1. 1 背景知识 1. 预处理(进行宏替换) 预处理 ( 进行宏替换 ) 预处理功能主要包括宏定义,文件包含,条件编译,去注释等。 预处理指令是以#号开头的代码行。 实例: gcc –E hello.c –o hello.i 选项“-E”,该选项的作用是让 gcc 在预处理结…...

树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法
树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作,无需更改相机配置。但是,一…...

安宝特方案丨XRSOP人员作业标准化管理平台:AR智慧点检验收套件
在选煤厂、化工厂、钢铁厂等过程生产型企业,其生产设备的运行效率和非计划停机对工业制造效益有较大影响。 随着企业自动化和智能化建设的推进,需提前预防假检、错检、漏检,推动智慧生产运维系统数据的流动和现场赋能应用。同时,…...

【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)
服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...
【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验
系列回顾: 在上一篇中,我们成功地为应用集成了数据库,并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了!但是,如果你仔细审视那些 API,会发现它们还很“粗糙”:有…...
css的定位(position)详解:相对定位 绝对定位 固定定位
在 CSS 中,元素的定位通过 position 属性控制,共有 5 种定位模式:static(静态定位)、relative(相对定位)、absolute(绝对定位)、fixed(固定定位)和…...
C++中string流知识详解和示例
一、概览与类体系 C 提供三种基于内存字符串的流,定义在 <sstream> 中: std::istringstream:输入流,从已有字符串中读取并解析。std::ostringstream:输出流,向内部缓冲区写入内容,最终取…...

【论文阅读28】-CNN-BiLSTM-Attention-(2024)
本文把滑坡位移序列拆开、筛优质因子,再用 CNN-BiLSTM-Attention 来动态预测每个子序列,最后重构出总位移,预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵(S…...
Spring是如何解决Bean的循环依赖:三级缓存机制
1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间互相持有对方引用,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...

Netty从入门到进阶(二)
二、Netty入门 1. 概述 1.1 Netty是什么 Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients. Netty是一个异步的、基于事件驱动的网络应用框架,用于…...

LLMs 系列实操科普(1)
写在前面: 本期内容我们继续 Andrej Karpathy 的《How I use LLMs》讲座内容,原视频时长 ~130 分钟,以实操演示主流的一些 LLMs 的使用,由于涉及到实操,实际上并不适合以文字整理,但还是决定尽量整理一份笔…...