互斥锁的所有权:

        互斥量的状态只有两种,开锁或闭锁(两种状态值)。当有线程持有它时,互斥量处于闭锁状态,由这个线程获得它的所有权。相反,当这个线程释放它时,将对互斥量进行开锁,失去它的所有权。当一个线程持有互斥量时,其他线程将不能够对它进行开锁或持有它,持有该互斥量的线程也能够再次获得这个锁而不被挂起,这个特性与一般的二值信号量有很大的不同:在信号量中,线程递归持有会发生主动挂起(最终形成死锁)。

一、为什么互斥量不能在中断服务例程中使用?

        首先必须明确一点,无论是在裸机还是RTOS实时操作系统,在中断服务ISR中,都要求中断处理快速执行,绝对不允许中断出现任何阻塞的操作,否则会影响确保其他任务的实时运行,破坏系统的稳定性。

        对于任何RTOS实时操作系统,在中断服务ISR中,无论是对于互斥锁 Mutex 还是 信号量 sem,绝对不允许出现任何可能阻塞中断处理的行为和操作。

        即:坚决不能在中断服务ISR中,调用 take mutex 或者 take sem。因为当其他线程中一旦已经获取 mutex 或 sem 时,当中断 INT 打断线程,进行中断上下文切换时,在中断服务ISR中,执行take mutex 或者 take sem操作,将使的整个中断进入阻塞状态。严重影响破坏整个系统的实时性和稳定性。

1根本原因:阻塞特性

互斥量(mutex)的核心特性是可能引发阻塞

  • 当互斥量已被占用时,rt_mutex_take() 会阻塞当前线程

  • 中断上下文不允许阻塞(必须快速执行并退出),因为 阻塞操作会触发线程调度rt_schedule(),保存线程切换时的上下文到TCB,但是 中断上下文没有线程控制块TCB可被调度使用。

2. 中断上下文限制

        中断服务例程 ISR 运行在中断上下文中,在中断中是没有所谓的线程上下文的(例如当前线程控制块),而互斥量的操作依赖于 Thread 线程上下文(eg:记录持有hold互斥量的当前线程)

同时源码中明确表示,在中断中禁用:

3. 优先级继承的不可行性

互斥量有优先级继承机制:

  • 中断没有"线程任务优先级"的概念,无法参与优先级继承

  • 中断没有线程控制块 TCBstruct rt_thread),没有办法去记录线程的优先级相关参数

总结: 为什么中断中不可以释放互斥锁(mutex)和 获取 mutex?

        互斥锁具有所有权概念,只有持有锁的线程才能释放它。中断上下文没有线程控制块(即没有线程身份),因此无法满足互斥锁的所有权要求。此外,互斥锁的释放操作可能涉及优先级继承的解除,这需要修改持有锁的线程的优先级,而中断上下文无法安全地执行这些操作(因为可能涉及调度,而中断中不能调度)。

二、线程多次持有互斥量的理解

1. 递归锁特性

        互斥量有一个特性叫做 " 递归锁(Recursive Lock)",即同一个线程可以多次获取(take)同一个互斥量,而不会造成死锁。每次获取互斥量后,必须对应相同次数的释放(release)操作,互斥量才会真正被释放给其他线程。

例如如下使用:

rt_mutex_t mutex;
void thread_function(void)
{// 第一次获取互斥量rt_mutex_take(mutex, RT_WAITING_FOREVER);// ... 执行一些操作 ...// 第二次获取同一个互斥量(同一个线程)rt_mutex_take(mutex, RT_WAITING_FOREVER); // 这里不会阻塞,因为已经持有该互斥量// ... 更多操作 ...// 第一次释放互斥量(互斥量仍然被持有,因为获取了两次)rt_mutex_release(mutex);// 第二次释放互斥量,此时互斥量才真正被释放rt_mutex_release(mutex);
}

Mutex 为什么需要多次获取?

        这种情况通常出现在递归函数中,或者在一个函数中调用了另一个函数,而这两个函数都需要操作同一个互斥量保护的数据。例如:

void function_a(void)
{rt_mutex_take(mutex, RT_WAITING_FOREVER);function_b(); // 这个函数内部也会获取同一个互斥量rt_mutex_release(mutex);
}
void function_b(void)
{rt_mutex_take(mutex, RT_WAITING_FOREVER);// 做一些操作rt_mutex_release(mutex);
}

        如果没有递归锁的特性那么当线程在`function_a`中已经持有互斥量,再进入`function_b`尝试获取同一个互斥量时,就会发生死锁(因为线程会等待自己释放互斥量)。而递归锁允许这种情况发生,因为同一个线程多次获取同一个互斥量是允许的。

 2. 递归深度

        RT-Thread的互斥量支持有限次数的递归获取(具体次数由`RT_MUTEX_VALUE_MAX`定义,默认是0xFFFF)。超过这个次数会导致获取失败。

3. 释放次数

        必须确保 互斥锁mutex 获取和释放的次数匹配,否则会导致互斥量无法被其他线程获取,或者提前释放导致其他线程错误地获取到互斥量。

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

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

相关文章

力扣32:最长有效括号

力扣32:最长有效括号题目思路代码题目 给你一个只包含 ‘(’ 和 ‘)’ 的字符串,找出最长有效(格式正确且连续)括号 子串 的长度。 左右括号匹配,即每个左括号都有对应的右括号将其闭合的字符串是格式正确的,比如 “…

机器学习实例应用

K最近邻算法K近邻算法(KNN,k-Nearest Neighbor),每个样本都可以用它的最接近的K个邻近值来代表。算法说明:①输入没有标签的新数据,将新数据的每个特征与样本集中数据对应的特征进行比较,然后算法提取样本集中特征最相似数据(最近…

力扣 hot100 Day77

连做了几个动态规划的中等题,还是比较有套路的,这里只简要分析一下最长递增子序列,设定dp[i]为以nums[i]结尾的最长子序列,递推公式就好推了乘积最大子数组,和上面类似,但考虑到负负得正,所以需…

深入解析RabbitMQ与AMQP-CPP:从原理到实战应用

一、RabbitMQ安装 1.安装 RabbitMQ sudo apt install rabbitmq-serverRabbitMQ 的简单使用 # 启动服务 sudo systemctl start rabbitmq-server.service # 查看服务状态 sudo systemctl status rabbitmq-server.service # 安装完成的时候默认有个用户 guest ,但是权限…

(论文速读)ViDAR:视觉自动驾驶预训练框架

论文题目:Visual Point Cloud Forecasting enables Scalable Autonomous Driving(视觉点云预测实现可扩展的自动驾驶) 会议:CVPR2024 摘要:与对通用视觉的广泛研究相比,可扩展视觉自动驾驶的预训练很少被探…

《Unity Shader入门精要》学习笔记二

1、基础光照(1)看世界的光模拟真实的光照环境来生成一张图像,需要考虑3种物理现象。光线从光源中被发射出来。光线和场景中的一些物体相交:一些光线被物体吸收了,而另一些光线被散射到其他方向摄像机吸收了一些光&…

Windchill 11.0使用枚举类型自定义实用程序实现生命周期状态管理

一、Enumerated Type Customization Utility 枚举类型自定义实用程序,可用于添加或编辑枚举类型的值,在Windchill 12.0+中可直接在类型和属性管理中编辑,如下图所示,而在Windchill 11.0中只能通过windchill shell启动程序,下面将详细介绍Windchill 11.0中启动并使用枚举类…

UGUI源码剖析(10):总结——基于源码分析的UGUI设计原则与性能优化策略

UGUI源码剖析(第十章):总结——基于源码分析的UGUI设计原则与性能优化策略 本系列文章对UGUI的核心组件与系统进行了深入的源代码级分析。本章旨在对前述内容进行系统性总结,提炼出UGUI框架最核心的设计原则,并基于这些…

STM32N6引入NPU,为边缘AI插上“隐形的翅膀”

2025年的春天格外特别。伴随着人形机器人、DeepSeek的强势刷屏,AI成了最有前景的赛道。万物皆可AI,万物也在寻觅用上AI或者让AI“转正”的“aha moment”。 帮助机器更好地“思考”,让更多的AI走向边缘,是AI发展的重要趋势之一。…

演练:使用VB开发多智能体协作的荣格八维分析器

在大语言模型高速发展的时代,我们面对困难的语义分析任务,通过构建智能体进行处理是一个流行趋势。本文将介绍如何使用 Visual Basic .NET 开发一个多智能体协作系统,用于分析聊天记录中特定人物的荣格八维人格类型。 本文使用 CC-BY-NC-SA …

llamafactory使用qlora训练

llamafactory使用qlora训练 1.环境搭建 conda create -n qlora python3.10 -y conda activate qlora# 克隆LLaMA-Factory仓库 git clone https://github.com/hiyouga/LLaMA-Factory.git# 进入仓库目录 cd LLaMA-Factory# 切换到0.9.4版本 git checkout v0.9.4pip install -e .2…

模型微调/量化技术整理

一、模型微调技术1.模型微调简介大模型微调(Fine-tuning),是指在已经预训练好的大语言模型基础上(基座模型),使用特定的数据集进行进一步训练,让模型适应特定任务或领域。通常LLM的预训练是无监督的,但微调…

实践笔记-VSCode与IDE同步问题解决指南;程序总是进入中断服务程序。

一、VSCode 修改文件后,IDE 未同步如果你在 VSCode 中异步修改了项目文件内容,但 S32DS 或 Keil(等集成开发环境)中的项目没有同步更新,有两个解决方法:检查文件是否已保存:确保 VSCode 中修改的…

C#WPF实战出真汁04--登录功能实现

1、登录功能实现要点对于登录系统,应该注意几个要点:用户认证流程设计,密码存储与验证,会话管理,防暴力破解措施,错误处理与提示2、登录功能的视图模型首先在xaml文件中必须指定该页面使用的视图模型&#…

鸿蒙入门简化版

第一步: 首先下载DEVStudio https://developer.huawei.com/consumer/cn/deveco-studio/ 第二步: 了解基本的ArkTs语言 https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/introduction-to-arkts 第三步 : 教学视频有两个途径&a…

day25|学习前端js

函数声明,被提升(hoisting)。函数表达式必须先定义才能用。对象解构,按属性名数组解构按顺序点运算符. 对象.属性名哪些可迭代(可以被for..of循环的东西):array,string,m…

quic协议与应用开发

quic为什么出现?quic主要是为了解决TCP协议的局限性而提出的,具体来说是要解决如下问题:1. 加密连接建立时间长TCP协议是传输层协议,而TLS是会话层协议,在Linux等主流操作系统中TCP在内核实现而TLS一般在用户态实现&am…

【浅学】tflite-micro + ESP32S3 + VScode + ESP-IDF 基于例程快速实现自己的图像分类模型训练部署全流程

如果你用Pytorch训练的模型那么可以参考我的步骤,使用的是Tensorflow的话参考官方文档即可,但流程都是一样的,每一步我都会提到部分操作细节及注意事项 官方教程 要详细学习的话tflite-micro里的微控制器章节下都详细看(页面左侧…

【HarmonyOS】应用设置全屏和安全区域详解

【HarmonyOS】应用设置全屏和安全区域详解 一、前言 IDE创建的鸿蒙应用,默认采取组件安全区布局方案。顶部会预留状态栏区域,底部会预留导航条区域。这就是所谓的安全区域。 如果不处理,界面效果很割裂。所以业内UI交互设计,都会设…

openfeign 只有接口如何创建bean的

OpenFeign 能够为纯接口创建 Spring Bean,其核心机制是通过动态代理和 Spring 的 FactoryBean 机制实现的。以下是详细的工作原理:1. EnableFeignClients 注解的启动在 Spring Boot 主类上添加 EnableFeignClients 注解:SpringBootApplicatio…