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

FreeRTOS_互斥量_学习笔记

互斥量

数值只有0或1
谁获得互斥量,就必须由谁释放同一个互斥量。在这里插入图片描述
但其实在freeRTOS中,任务A获取的互斥锁,任务B也能释放。因此谁上锁谁开锁只是约定,在程序实现上不是强制的。
可重入的函数"是指:多个任务同时调用它、任务和中断同时调用它,函数的运行也是安全的。可重入的函数也被称为"线程安全”(thread safe)。
每个任务都维持自己的栈、自己的CPU寄存器,如果一个函数只使用局部变量,那么它就是线程安全的。
函数中一旦使用了全局变量、静态变量、其他外设,它就不是"可重入的",如果该函数正在被调用,就必须阻止其他任务、中断再次调用它。
上述问题的解决方法是:任务A访问这些全局变量、函数代码时,独占它,就是上个锁。这些全局变量、函数代码必须被独占地使用,它们被称为临界资源。
互斥量的使用过程如下:

互斥量初始值为1
任务A想访问临界资源,先获得并占有互斥量,然后开始访问
任务B也想访问临界资源,也要先获得互斥量:被别人占有了,于是阻塞
任务A使用完毕,释放互斥量;任务B被唤醒、得到并占有互斥量,然后开始访问临界资源
任务B使用完毕,释放互斥量

互斥量函数

使用互斥量需要定义:

#define configUSE_MUTEXES 1

创建

成功则返回句柄,失败则返回NULL

SemaphoreHandle_t xSemaphoreCreateMutex( void ); // 动态分配
SemaphoreHandle_t xSemaphoreCreateMutexStatic( StaticSemaphore_t *pxMutexBuffer );

获取与释放

不能在中断中使用。除此之外与信号量相同

void vSemaphoreDelete( SemaphoreHandle_t xSemaphore );//删除
BaseType_t xSemaphoreGive( SemaphoreHandle_t xSemaphore );//释放
BaseType_t xSemaphoreTake(SemaphoreHandle_t xSemaphore, TickType_t xTicksToWait);//获取

优先级反转问题

使用信号量时,有时会出现低优先级先运行,高优先级不运行的问题,原因在于:
低优先级的任务先创建,先获取了信号量;
不需要取信号量的中优先级任务第二个创建,阻塞了低优先级任务,此时低优先级任务信号量还没释放;
高优先级任务后创建,此时take信号量,被阻塞,无法运行
在FreeRTOS_信号量_学习笔记中,修改三个任务的优先级:

    xTaskCreate(CarTask, "car1", 128, &g_cars[0], osPriorityNormal, NULL);xTaskCreate(Car2Task, "car2", 128, &g_cars[1], osPriorityNormal+1, NULL);xTaskCreate(Car3Task, "car3", 128, &g_cars[2], osPriorityNormal+2, NULL);	

同时将第二辆车的任务中获取信号量和释放信号量的语句删除。此时CarTask被Car2Task阻塞,Car3Task无法运行
此时,只要将信号量替换为互斥量即可解决优先级反转问题。其原理是用了优先级继承功能。
假设持有互斥锁的是任务A,如果更高优先级的任务B也尝试获得这个锁
任务B说:你既然持有宝剑,又不给我,那就继承我的愿望吧
于是任务A就继承了任务B的优先级
这就叫:优先级继承
等任务A释放互斥锁时,它就恢复为原来的优先级
互斥锁内部就实现了优先级的提升、恢复

递归锁

互锁

A获得互斥量M1
B获得互斥量M2
A还想获得M2才能运行,A阻塞
B还想获得M1才能运行,B阻塞
AB都阻塞,都无法释放其所持有的互斥量

自锁

A获得了互斥量M
他调用了一个库函数,库函数也想获取互斥量M
库函数阻塞,A休眠,无法释放互斥量

解决以上问题,可以使用递归锁,其特性为:

  1. 任务A获得递归锁M后,它还可以多次去获得这个锁
  2. "take"了N次,要"give"N次,这个锁才会被释放

递归锁的函数和一般互斥量的函数名不一样,参数类型一样。

递归锁互斥量
创建xSemaphoreCreateRecursiveMutexxSemaphoreCreateMutex
获得xSemaphoreTakeRecursivexSemaphoreTake
释放xSemaphoreGiveRecursivexSemaphoreGive

递归锁主要用于解决同一个线程多次获取同一个锁时的同步问题,不涉及多个线程之间的并发访问。

相关文章:

  • php 连接sqlserver步骤
  • 无网环境禁止 WPS 提示登录,且基本功能按钮可用
  • HQL面试题练习 —— 品牌营销活动天数
  • 运维的发展前景,会被AI取代吗?
  • python的requests爬虫模块使用代理ip方法---集合
  • python 庆余年2收视率数据分析与可视化
  • VUE3+TS+elementplus创建table,纯前端的table
  • Leaflet【二】图层绘制——UI图层【点线面】 矢量图层【img、svg】
  • Java NIO 基础
  • 使用DockerFile 编写 指令来构建镜像
  • continue插件二次开发调试并打包
  • notepad++ 批量转所有文件编码格式为UTF-8
  • c++中的constexpr 与decltype
  • 5.23 学习总结
  • Python KMP算法
  • (三)从jvm层面了解线程的启动和停止
  • 0x05 Python数据分析,Anaconda八斩刀
  • css的样式优先级
  • ES6系列(二)变量的解构赋值
  • es6要点
  • Java超时控制的实现
  • Java新版本的开发已正式进入轨道,版本号18.3
  • miaov-React 最佳入门
  • NSTimer学习笔记
  • SegmentFault 2015 Top Rank
  • Spring技术内幕笔记(2):Spring MVC 与 Web
  • VirtualBox 安装过程中出现 Running VMs found 错误的解决过程
  • 诡异!React stopPropagation失灵
  • 简单基于spring的redis配置(单机和集群模式)
  • 区块链将重新定义世界
  • 容器化应用: 在阿里云搭建多节点 Openshift 集群
  • 通过几道题目学习二叉搜索树
  • 一些基于React、Vue、Node.js、MongoDB技术栈的实践项目
  • 哈罗单车融资几十亿元,蚂蚁金服与春华资本加持 ...
  • ​Linux·i2c驱动架构​
  • $HTTP_POST_VARS['']和$_POST['']的区别
  • (01)ORB-SLAM2源码无死角解析-(66) BA优化(g2o)→闭环线程:Optimizer::GlobalBundleAdjustemnt→全局优化
  • (1)SpringCloud 整合Python
  • (2)空速传感器
  • (附源码)springboot家庭财务分析系统 毕业设计641323
  • (每日持续更新)信息系统项目管理(第四版)(高级项目管理)考试重点整理第3章 信息系统治理(一)
  • (三)docker:Dockerfile构建容器运行jar包
  • ./configure,make,make install的作用
  • .NET MVC之AOP
  • .net 调用海康SDK以及常见的坑解释
  • .NET 应用启用与禁用自动生成绑定重定向 (bindingRedirect),解决不同版本 dll 的依赖问题
  • .NetCore实践篇:分布式监控Zipkin持久化之殇
  • .NET的数据绑定
  • .net获取当前url各种属性(文件名、参数、域名 等)的方法
  • .NET性能优化(文摘)
  • .NET中使用Protobuffer 实现序列化和反序列化
  • @Mapper作用
  • @Pointcut 使用
  • @Repository 注解
  • @RequestMapping用法详解