鸿蒙Hi3861学习九-Huawei LiteOS-M(互斥锁)

news2024/11/16 3:08:17

一、简介

        互斥锁又被称为互斥型信号量,是一种特殊的二值信号量,用于实现对共享资源的独占式处理

        任意时刻互斥锁的状态只有两种:开锁闭锁

        当有任务占用公共资源时,互斥锁处于闭锁状态,这个任务获得该互斥锁的使用权。

        当该任务释放公共资源时,互斥锁被开锁,任务失去该互斥锁的所有权。

        当一个任务持有互斥锁时其他任务将不能再对该互斥锁进行开锁或持有

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

        更多关于互斥锁的概念以及优先级翻转问题的概念,可以参考如下链接:FreeRTOS学习五(信号量)_freertos信号量用法_t_guest的博客-CSDN博客

Mutex Management

二、 运行机制

        多任务环境下会存在多个任务访问同一公共资源的场景,而有些公共资源时非共享的,需要任务进行独占式处理。此时,就需要互斥锁出面了。

        用互斥锁处理非共享资源的同步访问时,如果有任务访问该资源,则互斥锁切换为闭锁状态。此时,其他任务如果想访问这个公共资源,则会被阻塞直到互斥锁被持有该锁的任务释放后,其他任务才能重新访问该公共资源,并且互斥锁会再次转换为闭锁状态。如此确保在同一时刻,只有一个任务正在访问这个公共资源,保证了公共资源操作的完整性

        优先级翻转,之前的文章中已经介绍过了,这里就不再过多介绍。有兴趣可以看上述的链接。

 三、API介绍

      osMutexNew

        函数功能:

        创建互斥锁。不可在中断中使用

        函数原型:

osMutexId_t osMutexNew(const osMutexAttr_t *attr)

        参数:

        attr:属性,自定义内存时使用。默认NULL

        返回值:

        锁标识符

        实例:

osMutexId_t mutex_id;
mutex_id = osMutexNew(NULL);

      osMutexAcquire

        函数功能:

        获取互斥锁。如果为闭锁状态,则阻塞任务等待直到超时为止。如果为开锁状态,则切换为闭锁状态。不可在中断中使用

        函数原型:

osStatus_t osMutexAcquire(osMutexId_t mutex_id, uint32_t timeout)

        参数:

        mutex_id:锁标识符。创建锁osMutexNew时获取

        timeout:等待超时时间。osWaitForever死等

        返回值:

        osOK:成功

        其他值:失败

        实例:

osMutexId_t mutex_id;
osMutexAcquire(mutex_id, osWaitForever);

      osMutexRelease

        函数功能:

        释放锁。如果锁为闭锁状态,释放后才能被其他任务获取到。不可在中断中使用

        函数原型:

osStatus_t osMutexRelease(osMutexId_t mutex_id)

        参数:

        mutex_id:锁标识符。创建锁osMutexNew时获取。

        返回值:

        osOK:成功

        其他值:失败

        实例:

osMutexId_t mutex_id;
osMutexRelease(mutex_id);

      osMutexDelete

        函数功能:

        删除锁。不可在中断中使用。

        函数原型:

osStatus_t osMutexDelete(osMutexId_t mutex_id)

        参数:

        mutex_id:锁标识符。创建锁osMutexNew时获取。

        返回值:

        osOK:成功

        其他值:失败

        实例:

osMutexId_t mutex_id;
osMutexDelete(mutex_id);

四、实例

        创建三个任务,三个任务的优先级递增。同时操作互斥锁,看看结果如何。

#define LOG_I(fmt, args...)   printf("<%8ld> - [TIMER]:"fmt"\r\n",osKernelGetTickCount(),##args);
#define LOG_E(fmt, args...)   printf("<%8ld>-[TIMER_ERR]>>>>>>>>>>>>:"fmt"\r\n",osKernelGetTickCount(), ##args);

osMutexId_t mutex_id;

void HighPrioThread(void)
{
  osDelay(50U);

  while (1)
  {
    LOG_I("HighPrioThread get before");
    osMutexAcquire(mutex_id, osWaitForever);
    LOG_I("HighPrioThread get after");

    osDelay(50U);

    LOG_I("HighPrioThread mutex release before");
    osMutexRelease(mutex_id);
    LOG_I("HighPrioThread mutex release after");
  }
}

void MidPrioThread(void)
{
  osDelay(10U);

  while (1)
  {
    LOG_I("MidPrioThread get before");
    osMutexAcquire(mutex_id, osWaitForever);
    LOG_I("MidPrioThread get after");

    osDelay(100);

    LOG_I("MidPrioThread mutex release before");
    osMutexRelease(mutex_id);
    LOG_I("MidPrioThread mutex release after");
  }
}

void LowPrioThread(void)
{
  while (1)
  {
    LOG_I("LowPrioThread get before");
    osMutexAcquire(mutex_id, osWaitForever);
    LOG_I("LowPrioThread get after");

    osDelay(200U);

    LOG_I("LowPrioThread mutex release before");
    osMutexRelease(mutex_id);
    LOG_I("LowPrioThread mutex release after");
  }
}

void Hello_World(void)
{
    LOG_I("Test mutex");

    mutex_id = osMutexNew(NULL);
    if (mutex_id == NULL)
    {
        LOG_E("Falied to create Mutex!\n");
    }

    osThreadAttr_t attr;

    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = 1024 * 4;

    attr.name = "HighPrioThread";
    attr.priority = osPriorityNormal2;

    if (osThreadNew((osThreadFunc_t)HighPrioThread, NULL, &attr) == NULL)
    {
        LOG_E("Falied to create HighPrioThread!\n");
    }

    attr.name = "MidPrioThread";
    attr.priority = osPriorityNormal1;

    if (osThreadNew((osThreadFunc_t)MidPrioThread, NULL, &attr) == NULL)
    {
        LOG_E("Falied to create MidPrioThread!\n");
    }

    attr.name = "LowPrioThread";
    attr.priority = osPriorityNormal;

    if (osThreadNew((osThreadFunc_t)LowPrioThread, NULL, &attr) == NULL)
    {
        LOG_E("Falied to create LowPrioThread!\n");
    }
}

        看结果:

         任务1优先级任务2优先级任务3优先级

        启动后,任务1延迟500ms执行任务2延迟100ms执行任务3不延迟

        注:以下编号与图片上编号对应

        1.任务3率先执行,先获取到互斥锁,使锁为闭锁状态。模拟操作共享数据。

        2.任务2延迟完成,开始执行,获取互斥锁,发现为闭锁状态,则挂起任务等待。

        3.任务1延迟完成,开始执行,获取互斥锁,发现为闭锁状态,则挂起任务等待。

        4.任务3数据操作完成,释放互斥锁。

        5.任务1因为优先级最高即使任务2先等待,但是还是任务1抢占到控制权然后获取互斥锁。然后开始操作数据。

        6.任务3继续执行。

        7.任务3获取互斥锁,发现为闭锁状态,则挂起任务等待。

        8.9。任务1继续执行

        10.任务1获取互斥锁。虽然任务1刚才释放了互斥锁,但是任务2一直在等待互斥锁,在任务1释放的瞬间就获取到互斥锁了。所以这里即使任务1优先级高,也无法获取到互斥锁。

        11.任务2模拟操作数据

        12.任务2操作数据完成,释放互斥锁。

        13.任务1因为优先级高,这里获取到互斥锁,模拟操作数据。

        这里可能会有疑问,为什么在10阶段,任务2明明优先级低,却能获取到互斥锁。而13这里任务3缺获取不到。这是因为在10阶段,任务2是在任务1释放互斥锁时,等待任务队列中优先级最高的任务。而13阶段,任务2在释放信号量时,任务1早已经在等待了。任务1是等待队列中优先级最高的。所以互斥锁才会被任务1截胡。

        从运行结果可以看出来,在同时等待互斥锁时,高优先级的任务总会有限获取到信号量,跟等待顺序是无关的。

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

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

相关文章

C++系列六:一文打尽C++运算符

C运算符 1. 算术运算符2. 关系运算符3. 逻辑运算符4. 按位运算符5. 取地址运算符6. 取内容运算符7. 成员选择符8. 作用域运算符9. 总结 1. 算术运算符 算术运算符用于执行基本数学运算&#xff0c;例如加减乘除和取模等操作。下表列出了C中支持的算术运算符&#xff1a; 运算…

Oracle 19C 单机环境升级RU(19.3升级至19.12)

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3; 哈喽&#xff01;大家好&#xff0c;我是【IT邦德】&#xff0c;江湖人称jeames007&#xff0c;10余年DBA及大数据工作经验 一位上进心十足的【大数据领域博主】&#xff01;&#x1f61c;&am…

鸿蒙Hi3861学习五-Huawei LiteOS-M(任务管理)

一、任务简介 关于任务的相关介绍&#xff0c;之前文章有比较详细的介绍&#xff0c;这里不做过多解释&#xff0c;可以参考如下文章&#xff1a;FreeRTOS学习二&#xff08;任务&#xff09;_t_guest的博客-CSDN博客 而LiteOS的主要特性可以总结为如下几点&#xff1a; LiteO…

〖数据挖掘〗weka3.8.6的安装与使用

目录 背景 一、安装 二、使用explorer 1. 介绍 2.打开自带的数据集(Preprocess) 1.打开步骤 2.查看属性和数据编辑 3.classify 4.Cluster 5.Associate 6.Select attributes 7.Visualize 待补充 背景 Weka的全名是怀卡托智能分析环境&#xff08;Waikato Environme…

低代码平台解读—如何不写代码创建表单和维护表单

工作表新建与修改——敲敲云 新建工作表的流程包含 新建工作表/编辑公祖表为工作表添加字段&#xff0c;例如“员工档案”表中有姓名、性别、年龄等字段为字段设置属性工作表布局工作表预览、保存、关闭 1、新建工作表/修改工作表 新建工作表 修改工作表 2、为工作表添加字段 …

c#笔记-定义类

声明类 类可以使用帮助你管理一组相互依赖的数据&#xff0c;来完成某些职责。 类使用class关键字定义&#xff0c;并且必须在所有顶级语句之下。 类的成员只能有声明语句&#xff0c;不能有执行语句。 class Player1 {int Hp;int MaxHp;int Atk;int Def;int Overflow(){if (…

算法记录 | Day55 动态规划

392.判断子序列 思路&#xff1a; 1.确定dp数组&#xff08;dp table&#xff09;以及下标的含义: dp[i][j] 表示以下标i-1为结尾的字符串s&#xff0c;和以下标j-1为结尾的字符串t&#xff0c;相同子序列的长度为dp[i][j]。 2.确定递推公式&#xff1a; if (s[i - 1] t[…

线程同步、生产者消费模型和POSIX信号量

gitee仓库&#xff1a; 1.阻塞队列代码&#xff1a;https://gitee.com/WangZihao64/linux/tree/master/BlockQueue 2.环形队列代码&#xff1a;https://gitee.com/WangZihao64/linux/tree/master/ringqueue 条件变量 概念 概念&#xff1a; 利用线程间共享的全局变量进行同…

单片机c51中断 — 开关状态监测

项目文件 文件 关于项目的内容知识点可以见专栏单片机原理及应用 的第五章&#xff0c;中断 图中 P2.0引脚处接有一个发光二极管 D1&#xff0c;P3.2引脚处接有一个按键。要求分别采用一般方式和中断方式编程实现按键压下一次&#xff0c;D1 的发光状态反转一次的功能。 查询…

从C语言到C++⑦(第二章_类和对象_下篇)初始化列表+explicit+static成员+友元+内部类+匿名对象

目录 1. 构造函数的初始化列表 1.1 初始化列表概念 1.2 初始化列表注意事项 2. 构造函数的explicit关键字 2.1 C语言的隐式类型转换 2.2 explicit 关键字使用 3. static成员 3.1 static的概念 3.2 static成员特性 3.3 static成员使用场景 4. 友元&#xff08;frien…

【Java 基础】类和对象 方法重载详解

《Java 零基础入门到精通》专栏持续更新中。通过本专栏你将学习到 Java 从入门到进阶再到实战的全套完整内容,所有内容均将集中于此专栏。无论是初学者还是有经验的开发人员,都可从本专栏获益。 订阅专栏后添加我微信或者进交流群,进群可找我领取 前端/Java/大数据/Python/低…

Linux 常用命令(1)

文章目录 Linux 常用命令格式 clear 清屏清屏获取当前目录的路径 pwd目录切换命令 cd进入上一级目录进入当前目录的文件夹 ta中(假设这里有一个文件夹ta)进入主目录进入根目录 显示目录内容 ls显示详细信息&#xff0c;包含文件属性显示全部内容&#xff0c;包含隐藏文件&#…

tiechui_lesson07_中断级和自旋锁

一、中断级IRQL 高级别可以打断低级别的调用&#xff0c;同级别不能打断同级别的调用。 中断级在软件层面分为三级&#xff0c;再高的级别是硬件发送的中断。 - 0 pass_level- 1 apc_level- 2 dpc_level 只有硬件中断能打断 1.获取中断级 DbgPrint("当前执行中断级为 %…

无法防范的网络攻击-DDOS

DDoS攻击&#xff08;Distributed Denial of Service Attack&#xff09;是一种网络攻击方式&#xff0c;攻击者通过利用大量的计算机或者网络设备向目标服务器发送大量的请求&#xff0c;使得目标服务器无法正常响应合法用户的请求&#xff0c;从而导致服务不可用或者服务质量…

M302H-YS-Hi3798MV300H/MV310-当贝纯净桌面卡刷固件包

M302H-YS-Hi3798MV300H&#xff0f;MV310-当贝纯净桌面卡刷固件包-内有教程及短接点提示 特点&#xff1a; 1、适用于对应型号的电视盒子刷机&#xff1b; 2、开放原厂固件屏蔽的市场安装和u盘安装apk&#xff1b; 3、修改dns&#xff0c;三网通用&#xff1b; 4、大量精简…

LicheePi4A尝鲜开箱笔记

开发板介绍 LicheePi4A是以 TH1520 主控核心&#xff0c;搭载 4TOPSint8 AI 算力的 NPU&#xff0c;支持双屏 4K 显示输出&#xff0c;支持 4K 摄像头接入&#xff0c;双千兆 POE 网口和多个 USB 接口&#xff0c;音频由 C906 核心处理。 LicheePi4A详细介绍可以在https://wi…

SpringCloud 微服务系列——Spring Cloud Alibaba 微服务工具集

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

FreeRTOS内核:详解Task各状态(GPT4帮写)

FreeRTOS内核&#xff1a;详解Task各状态&#xff08;GPT4帮写&#xff09; 1. 背景2. Task顶层状态区分3. 运行状态&#xff08;Running&#xff09;4. 非运行状态4.1 阻塞态&#xff08;Blocked&#xff09;&#xff1a;4.2 挂起态&#xff08;Suspended&#xff09;4.3 就绪…

K8s基础8——svc基础使用、应用暴露、iptables代理、ipvs代理

文章目录 一、Service基本了解二、Service定义与创建2.1 相关命令2.2 yaml文件参数大全2.3 创建svc2.3.1 两种创建方式类比2.3.2 验证集群内A应用访问B应用2.3.3 将集群外服务定义为K8s的svc2.3.4 分配多个端口 2.4 常用三种类型2.4.1 ClusterIP&#xff08;集群内部访问&#…

如何解决Redis的双写一致性

目录 1.更新策略2.问题场景3.解决方案 1.更新策略 Redis和MySQL的默认的更新策略是旁路缓存策略&#xff0c;旁路缓存策略又有写策略和读策略 写策略&#xff1a;更新时&#xff0c;先更新数据库&#xff0c;再更新缓存 读策略&#xff1a;读取数据时&#xff0c;如果命中缓…