ESP32移植Openharmony设备开发---(6)Mutex互斥锁

news2024/11/26 11:05:07

Mutex互斥锁

官方文档:OpenAtom OpenHarmony

基本概念

互斥锁又称互斥型信号量,用于实现对共享资源的独占式处理。当有任务持有时,这个任务获得该互斥锁的所有权。当该任务释放它时,任务失去该互斥锁的所有权。当一个任务持有互斥锁时,其他任务将不能再持有该互斥锁。多任务环境下往往存在多个任务竞争同一共享资源的应用场景,互斥锁可被用于对共享资源的保护从而实现独占式访问。

互斥锁属性包含3个属性:协议属性、优先级上限属性和类型属性。协议属性用于处理不同优先级的任务申请互斥锁,协议属性包含如下三种:

  • LOS_MUX_PRIO_NONE 不对申请互斥锁的任务的优先级进行继承或保护操作。
  • LOS_MUX_PRIO_INHERIT 优先级继承属性,默认设置为该属性,对申请互斥锁的任务的优先级进行继承。在互斥锁设置为本协议属性情况下,申请互斥锁时,如果高优先级任务阻塞于互斥锁,则把持有互斥锁任务的优先级备份到任务控制块的优先级位图中,然后把任务优先级设置为和高优先级任务相同的优先级;持有互斥锁的任务释放互斥锁时,从任务控制块的优先级位图恢复任务优先级。
  • LOS_MUX_PRIO_PROTECT 优先级保护属性,对申请互斥锁的任务的优先级进行保护。在互斥锁设置为本协议属性情况下,申请互斥锁时,如果任务优先级小于互斥锁优先级上限,则把任务优先级备份到任务控制块的优先级位图中,然后把任务优先级设置为互斥锁优先级上限属性值;释放互斥锁时,从任务控制块的优先级位图恢复任务优先级。

互斥锁的类型属性用于标记是否检测死锁,是否支持递归持有,类型属性包含如下三种:

  • LOS_MUX_NORMAL 普通互斥锁,不会检测死锁。如果任务试图对一个互斥锁重复持有,将会引起这个线程的死锁。如果试图释放一个由别的任务持有的互斥锁,或者如果一个任务试图重复释放互斥锁都会引发不可预料的结果。
  • LOS_MUX_RECURSIVE 递归互斥锁,默认设置为该属性。在互斥锁设置为本类型属性情况下,允许同一个任务对互斥锁进行多次持有锁,持有锁次数和释放锁次数相同,其他任务才能持有该互斥锁。如果试图持有已经被其他任务持有的互斥锁,或者如果试图释放已经被释放的互斥锁,会返回错误码。
  • LOS_MUX_ERRORCHECK 错误检测互斥锁,会自动检测死锁。在互斥锁设置为本类型属性情况下,如果任务试图对一个互斥锁重复持有,或者试图释放一个由别的任务持有的互斥锁,或者如果一个任务试图释放已经被释放的互斥锁,都会返回错误码。

运行机制

多任务环境下会存在多个任务访问同一公共资源的场景,而有些公共资源是非共享的,需要任务进行独占式处理。互斥锁怎样来避免这种冲突呢?

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

小型系统互斥锁运作示意图

BUILD.gn

# Copyright (c) 2022 Hunan OpenValley Digital Industry Development Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import("//kernel/liteos_m/liteos.gni")

module_name = get_path_info(rebase_path("."), "name")
kernel_module(module_name){
    sources = [
        "LOS_Mutex_example.c"
    ]
    
    include_dirs = [
        "//kernel/liteos_m/kernel/include"
    ]
}

LOS_Mutex_example

/*
 * Copyright (c) 2022 Hunan OpenValley Digital Industry Development Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "los_event.h"
#include "los_mux.h"
#include "los_task.h"
#include "ohos_run.h"

#ifndef osWaitForever
#define osWaitForever 0xFFFFFFFFU
#endif

#define EVENT_MASK_CLEAN 0x00000001
#define MAX_STR_LEN 256
#define DELAY_100_TICKS 100U
#define DELAY_400_TICKS (4 * DELAY_100_TICKS)
#define DELAY_600_TICKS (6 * DELAY_100_TICKS)
#define TASK_STACK_SIZE 4096
#define TASK_PRIO 5

UINT32 mutex1_id;
UINT32 mutex2_id;

static char g_str[MAX_STR_LEN];

void firstThread(UINT32 arg)
{
    int ret = -1;
    while (1) {
        LOS_MuxPend(mutex1_id, osWaitForever);
        ret = strcpy_s(g_str, MAX_STR_LEN, "firstThread");
        if (ret != 0) {
            printf("strcpy_s fail!\r\n");
        }
        printf("firstThread is Acquire. g_str=%s\r\n", g_str);
        LOS_MuxPost(mutex1_id);
        LOS_TaskDelay(DELAY_100_TICKS);
    }
}

void secondThread(UINT32 arg)
{
    int ret = -1;
    while (1) {
        LOS_MuxPend(mutex2_id, osWaitForever);
        char tmp[MAX_STR_LEN] = {0};
        ret = sprintf_s(tmp, MAX_STR_LEN, "%s+secondThread", g_str);
        if (ret < 0) {
            printf("sprintf_s fail!\r\n");
        }

        ret = memcpy_s(g_str, MAX_STR_LEN, tmp, sizeof(tmp));
        if (ret != 0) {
            printf("memcpy_s fail!\r\n");
        }
        printf("secondThread is Acquire. g_str=%s\r\n", g_str);
        LOS_MuxPost(mutex2_id);
        LOS_TaskDelay(DELAY_100_TICKS);
    }
}

void thirdThread(UINT32 arg)
{
    int ret;
    while (1) {
        LOS_MuxPend(mutex1_id, osWaitForever);
        LOS_MuxPend(mutex2_id, osWaitForever);
        char tmp[MAX_STR_LEN] = {0};
        ret = sprintf_s(tmp, MAX_STR_LEN, "%s+thirdThread", g_str);
        if (ret < 0) {
            printf("sprintf_s fail!\r\n");
        }

        ret = memcpy_s(g_str, MAX_STR_LEN, tmp, sizeof(tmp));
        if (ret != 0) {
            printf("memcpy_s fail!\r\n");
        }
        printf("thirdThread is Acquire. g_str=%s\r\n", g_str);
        LOS_TaskDelay(DELAY_100_TICKS);
        LOS_MuxPost(mutex1_id);
        LOS_TaskDelay(DELAY_400_TICKS);
        LOS_MuxPost(mutex2_id);
        LOS_TaskDelay(DELAY_600_TICKS);
    }
}

void os_mutex_example(void)
{
    int ret = -1;
    ret = memset_s(g_str, MAX_STR_LEN, 0, MAX_STR_LEN);
    if (ret != 0) {
        printf("memset_s fail!\r\n");
    }
    TSK_INIT_PARAM_S attr = {0};
    attr.uwStackSize = TASK_STACK_SIZE;
    attr.usTaskPrio = TASK_PRIO;

    // 创建互斥锁
    if (LOS_MuxCreate(&mutex1_id) != LOS_OK) {
        printf("create Mutex1 failed!  ret=%x\n", ret);
        return;
    }

    if (LOS_MuxCreate(&mutex2_id) != LOS_OK) {
        printf("create Mutex2 failed!\n");
        LOS_MuxDelete(mutex1_id);
        return;
    }

    // 锁任务调度
    LOS_TaskLock();
    attr.pcName = "firstThread";
    attr.pfnTaskEntry = (TSK_ENTRY_FUNC)firstThread;
    UINT32 taskIDFirst;
    if (LOS_TaskCreate(&taskIDFirst, &attr) != LOS_OK) {
        printf("create firstThread failed!\n");
        LOS_MuxDelete(mutex1_id);
        LOS_MuxDelete(mutex2_id);
        return;
    }
    attr.pcName = "secondThread";
    attr.pfnTaskEntry = (TSK_ENTRY_FUNC)secondThread;
    UINT32 taskIDTwo;
    if (LOS_TaskCreate(&taskIDTwo, &attr) != LOS_OK) {
        printf("create secondThread failed!\n");
    }
    attr.pcName = "thirdThread";
    attr.pfnTaskEntry = (TSK_ENTRY_FUNC)thirdThread;
    UINT32 taskIDThree;
    if (LOS_TaskCreate(&taskIDThree, &attr) != LOS_OK) {
        printf("create thirdThread failed!\n");
    }
    LOS_TaskUnlock(); // 解锁任务调度
}

OHOS_APP_RUN(os_mutex_example);

代码分析:

  • firstThread|secondThread|、thirdThread:循环中尝试获取mutex1_id,然后修改g_str的值,添加上自己的标识,并打印当前线程获得互斥锁后的g_str值。释放互斥锁并延时一段时间。

互斥锁同步行为分析

  • firstThreadsecondThread 分别对不同的互斥锁进行操作(互斥锁id不同),所以可以并行执行
  • thirdThread 则需要同时获得两个互斥锁,这意味着它将在其他两个任务释放各自的互斥锁后才能继续执行。这种情况下,thirdThread 的执行会依赖于firstThreadsecondThread 的进度。

API参考

LOS_MuxCreate()
UINT32 LOS_MuxCreate(UINT32 *muxHandle);

描述:

创建互斥锁

参数:

名字

描述

muxHandle

互斥锁id

LOS_MuxPend()
UINT32 LOS_MuxPend(UINT32 muxHandle, UINT32 timeout);

描述:

获取互斥锁

参数:

名字

描述

muxHandle

互斥锁id,由LOS_MuxCreate创建得到

timeout

delay时间

LOS_MuxPost()
UINT32 LOS_MuxPost(UINT32 muxHandle);

描述:

释放互斥锁

参数:

名字

描述

muxHandle

互斥锁id,由LOS_MuxCreate创建得到

LOS_MuxDelete()
UINT32 LOS_MuxDelete(UINT32 muxHandle);

描述:

删除互斥锁

参数:

名字

描述

muxHandle

互斥锁id,由LOS_MuxCreate创建得到

编译并烧录

修改工作文件夹级的BUILD.gn文件,将编译的文件夹指定为新建的005_LOS_Mutex

在源码根目录下使用hb工具对写好的代码进行编译

选择mini级系统

同理 产品选择esp公司下的esp32

选择完毕后在源码根目录下执行hb build -f 进行编译

编译完成后会有如下界面,并且编译后的代码固件位于:out\esp32\esp32

验证结果

打开串口工具->选择COM5->打开串口

按下ESP32开发板上的EN键,即可观察到实验现象:

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

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

相关文章

2024年最新苹果iOS证书申请创建App详细图文流程

iOS 证书设置指南&#xff1a; 对于开发者来说&#xff0c;在没有Mac电脑或对Xcode等开发工具不熟悉的情况下&#xff0c;如何快速完成IOS证书制作和IPA文件提交至开发者中心一直是一个难题。但是现在&#xff0c;有了初雪云提供的极简工具&#xff0c;您可以轻松实现这两个任…

Appium中的api(一)

目录 1.基础python代码准备 1--参数的一些说明 2--python内所要编写的代码 解释 2.如何获取包名和界面名 1-api 2-完整代码 代码解释 3.如何关闭驱动连接 4.安装卸载app 1--卸载 2--安装 5.判断app是否安装 6.将应用放到后台在切换为前台的时间 7.UIAutomatorViewer的使用 1--找…

git rebase的常用场景: 交互式变基, 变基和本地分支基于远端分支的变基

文章目录 作用应用场景场景一&#xff1a;交互式变基(合并同一条线上的提交记录) —— git rebase -i HEAD~2场景二&#xff1a;变基(合并分支) —— git rebase [其他分支名称]场景三&#xff1a;本地分支与远端分支的变基 作用 使git的提交记录变得更加简洁 应用场景 场景…

【华为HCIP实战课程十六】OSPF虚链路Vlink,网络工程师

一、vlink续 区域内部的路由优于区域之间的路由,区域之间优于外部路由,外部路由类型1优于外部类型2 只有同一级别的路由才会对比cost <R3>tracert 11.1.1.1 traceroute to 11.1.1.1(11.1.1.1), max hops: 30 ,packet length: 40,press CTRL_C to break 1 10.1.35.5 …

Wave-Mamba 论文总结

题目&#xff1a;Exchange&#xff08;交换&#xff09; Wave-Mamba: Wavelet State Space Model&#xff08;小波状态空间模型&#xff09;for Ultra-High-Definition&#xff08;超高清&#xff09;Low-Light Image Enhancement&#xff08;弱光图像增强&#xff09; 论文&am…

stm32单片机基于rt-thread 的 串行 Flash 通用驱动库 SFUD 的使用

1024程序员节&#xff5c;征文 一、sfud 通用驱动库介绍 SFUD 是一款开源的串行 SPI Flash 通用驱动库。由于现有市面的串行 Flash 种类居多&#xff0c;各个 Flash 的规格及命令存在差异&#xff0c; SFUD 就是为了解决这些 Flash 的差异现状而设计&#xff0c;能够支持不同品…

二叉树习题其一Java【力扣】【算法学习day.8】

前言 书接上篇文章介绍的链表基础知识—>二叉树理论&#xff0c;这篇文章我们将通过习题来掌握哈希表的使用。 ###我做这类文档一个重要的目的还是给正在学习的大家提供方向&#xff08;例如想要掌握基础用法&#xff0c;该刷哪些题&#xff1f;&#xff09;我的解析也不会…

PHP多功能图片编辑器

PHP多功能图片编辑器 前言效果图功能说明平台支持情况部分源码领取源码下期更新 前言 PHP多功能图片编辑器 工具箱网站源码无需数据库上传即用&#xff0c;测试了一下还可以&#xff0c;免费分享自行研究。 效果图 功能说明 ✓ 无需上传&#xff0c;使用浏览器自身进行转换 …

049_python基于Python的热门微博数据可视化分析

目录 系统展示 开发背景 代码实现 项目案例 获取源码 博主介绍&#xff1a;CodeMentor毕业设计领航者、全网关注者30W群落&#xff0c;InfoQ特邀专栏作家、技术博客领航者、InfoQ新星培育计划导师、Web开发领域杰出贡献者&#xff0c;博客领航之星、开发者头条/腾讯云/AW…

多模态大语言模型(MLLM)-Deepseek Janus

论文链接&#xff1a;https://arxiv.org/abs/2410.13848 代码链接&#xff1a;https://github.com/deepseek-ai/Janus 本次解读Janus: Decoupling Visual Encoding for Unified Multimodal Understanding and Generation 前言 Deepseek出品&#xff0c;必属精品。 创新点 传…

如何在Java应用中发送短信

很多业务场景里&#xff0c;我们都需要发送短信&#xff0c;比如登陆验证码、告警、营销通知、节日祝福等等。 这篇文章&#xff0c;我们聊聊 Java 应用中如何优雅的发送短信。 1 客户端/服务端两种模式 Java 应用中发送短信通常需要使用短信服务提供商提供的短信 API 。 我…

多ip访问多网站

多IP访问多网站 1.预配操作 [rootlocalhost ~]# mount /dev/sr0 /mnt mount: /mnt: WARNING: source write-protected, mounted read-only. [rootlocalhost ~]# systemctl stop firewalld ----------关闭防火墙 [rootlocalhost ~]# setenforce 0 -------关闭selinux2.安装n…

技术人员的自我修炼:在变化中成长

引言 在技术的海洋中&#xff0c;我们每个人都是一名探索者&#xff0c;不断学习、适应、成长。作为一名技术人员&#xff0c;我们不仅要面对自身技能的提升和心态的调整&#xff0c;还要应对外部环境的不断变化。本文将探讨技术人员如何在内部修炼和外部适应中找到平衡&#…

UE5 喷射背包

首选创建一个输入操作 然后在输入映射中添加&#xff0c;shift是向上飞&#xff0c;ctrl是向下飞 进入人物蓝图中编写逻辑&#xff0c;变量HaveJatpack默认true&#xff0c;Thrust为0 最后

【C语言】编译和链接(编译环境和运行环境)

文章目录 一、翻译环境和运行环境二、翻译环境1.编译预处理编译汇编 2.链接 四、运行环境 一、翻译环境和运行环境 在 ANSI C 的任何⼀种实现中&#xff0c;存在两个不同的环境&#xff0c;如下&#xff1a; 翻译环境&#xff1a;在翻译环境中&#xff0c;会通过编译和链接两个…

鸿蒙软件开发中常见的如何快速自动生成二维码?QRCode组件

QRCode 用于显示单个二维码的组件。 说明&#xff1a; 该组件从API Version 7开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。 二维码组件的像素点数量与内容有关&#xff0c;当组件尺寸过小时&#xff0c;可能出现无法展示内容的情况&…

在 Controller 层对系统作防御性编程

简介 Web 开发中无论是 MVC 还是 DDD 架构 Controller 层都是系统的门面&#xff0c;既对外的接口&#xff0c;对内的接口&#xff0c;一般情况下任何错误必须组织在 Controller 层 如何作 在 Controller 层中的接口使用 try-catch Slf4j RestController("/") Re…

MobileNetV2实现实时口罩检测tensorflow

项目源码获取方式见文章末尾&#xff01; 回复暗号&#xff1a;13&#xff0c;免费获取600多个深度学习项目资料&#xff0c;快来加入社群一起学习吧。 **《------往期经典推荐------》**项目名称 1.【Informer模型复现项目实战】 2.【卫星图像道路检测DeepLabV3Plus模型】 3.【…

[LeetCode] 230. 二叉搜索树中第K小的元素

题目描述&#xff1a; 给定一个二叉搜索树的根节点 root &#xff0c;和一个整数 k &#xff0c;请你设计一个算法查找其中第 k 小的元素&#xff08;从 1 开始计数&#xff09;。 示例 1&#xff1a; 输入&#xff1a;root [3,1,4,null,2], k 1 输出&#xff1a;1示例 2&am…

《计算机视觉》—— 基于 dlib 库的方法将两张人脸图片进行换脸

声明&#xff1a;此篇文章所用的明星照片只为用于演示代码的效果&#xff0c;无诋毁她人肖像之意 一、案例实现的思想 此案例的核心是基于人脸68个关键点检测模型来实现的&#xff0c;人脸68个关键带点检测后的效果如下&#xff1a; 通过对上图中红色区域的转换&#xff0c;…