22 鸿蒙LiteOS 互斥锁(Mutex)实战教程:多任务共享资源保护

鸿蒙LiteOS 互斥锁(Mutex)实战教程:多任务共享资源保护

一、前言

在鸿蒙 OpenHarmony LiteOS 多任务开发中,多个任务经常会同时访问同一个全局变量、外设、串口等共享资源 。如果不做保护,会出现数据读写混乱、逻辑异常等问题。

互斥锁(Mutex) 就是专门用来解决这个问题的:同一时间只允许一个任务持有锁,访问共享资源,保证数据安全。

本文基于官方示例源码,讲解互斥锁原理、API、代码解析、运行现象,同时对比互斥锁与信号量的核心区别,适合鸿蒙嵌入式入门学习。

哔站视频《【RK2206 鸿蒙LiteOS 实战 07】什么是互斥,互斥有什么用》:https://www.bilibili.com/video/BV1ed5X61E7t/

哔站视频《06:RK2206 OpenHarmonyOS 鸿蒙 软件定时器与硬件定时器区别 软件定时器与任务区别 软件定时器实战》:https://www.bilibili.com/video/BV1w3546DEBS/?vd_source=3a9dd7a328acafb09dd1b8d05f3e2bf7

哔站视频《05:RK2206 OpenHarmonyOS 鸿蒙 什么是信号量 为什么需要信号量 代码演示》:https://www.bilibili.com/video/BV1to5W6pETF/?vd_source=3a9dd7a328acafb09dd1b8d05f3e2bf7

哔站视频《04:RK2206 OpenHarmonyOS 鸿蒙 任务实战》:https://www.bilibili.com/video/BV15R5E6JEHy/

哔站视频《03:RK2206 鸿蒙 LiteOS 如何通过控制编译选项编译不同案例》:https://www.bilibili.com/video/BV15e5J6QEGY/?spm_id_from=333.1387.homepage.video_card.click&vd_source=3a9dd7a328acafb09dd1b8d05f3e2bf7

哔站视频《02:RK2206 鸿蒙 LiteOS bin 文件 烧写》:https://www.bilibili.com/video/BV1pcRdBaEAt/?spm_id_from=333.1387.homepage.video_card.click&vd_source=3a9dd7a328acafb09dd1b8d05f3e2bf7

哔站视频《01:RK2206 鸿蒙 LiteOS ubuntu 开发环境 全程 安装配置》:https://www.bilibili.com/video/BV1nrRkBoEMR/?spm_id_from=333.1387.homepage.video_card.click&vd_source=3a9dd7a328acafb09dd1b8d05f3e2bf7

二、互斥锁核心概念

1. 什么是互斥锁

互斥锁是一种特殊的二值信号量 ,用于多任务对共享资源的独占式访问

  • 只有0 和 1 两个状态
  • 一个任务获取锁后,其他任务必须等待
  • 解锁后,其他任务才能获取锁继续执行

2. 互斥锁作用

  • 保护共享资源(全局变量、硬件外设、文件等)
  • 防止多任务同时读写导致数据错乱
  • 实现任务间独占式访问

3. 核心API

函数 作用
LOS_MuxCreate 创建互斥锁
LOS_MuxPend 申请互斥锁(拿不到就阻塞等待)
LOS_MuxPost 释放互斥锁
LOS_MuxDelete 删除互斥锁

三、完整可运行源码

c 复制代码
#include "los_task.h"
#include "ohos_init.h"

static unsigned int m_mutex_id;  // 互斥锁句柄
static unsigned int m_data = 0;  // 共享资源(全局变量)

/***************************************************************
* 函数名称: write_thread
* 说    明: 写数据线程
* 参    数: 无
* 返 回 值: 无
***************************************************************/
void write_thread()
{
    while (1)
    {
        // 申请互斥锁
        LOS_MuxPend(m_mutex_id, LOS_WAIT_FOREVER);

        m_data++;  // 修改共享资源
        printf("write_thread write data:%u\n", m_data);

        LOS_Msleep(3000);  // 模拟占用资源

        // 释放互斥锁
        LOS_MuxPost(m_mutex_id);
    }
}

/***************************************************************
* 函数名称: read_thread
* 说    明: 读数据线程
* 参    数: 无
* 返 回 值: 无
***************************************************************/
void read_thread()
{
    LOS_Msleep(1000);  // 延时1s启动

    while (1)
    {
        // 申请互斥锁
        LOS_MuxPend(m_mutex_id, LOS_WAIT_FOREVER);

        printf("read_thread read data:%u\n", m_data);  // 读取共享资源

        LOS_Msleep(1000);

        // 释放互斥锁
        LOS_MuxPost(m_mutex_id);
    }
}

/***************************************************************
* 函数名称: mutex_example
* 说    明: 互斥锁初始化入口
* 参    数: 无
* 返 回 值: 无
***************************************************************/
void mutex_example()
{
    unsigned int thread_id1;
    unsigned int thread_id2;
    TSK_INIT_PARAM_S task1 = {0};
    TSK_INIT_PARAM_S task2 = {0};
    unsigned int ret = LOS_OK;

    // 创建互斥锁
    ret = LOS_MuxCreate(&m_mutex_id);
    if (ret != LOS_OK)
    {
        printf("Falied to create Mutex\n");
    }

    // 创建写任务
    task1.pfnTaskEntry = (TSK_ENTRY_FUNC)write_thread;
    task1.uwStackSize = 2048;
    task1.pcName = "write_thread";
    task1.usTaskPrio = 24;
    ret = LOS_TaskCreate(&thread_id1, &task1);
    if (ret != LOS_OK)
    {
        printf("Falied to create write_thread ret:0x%x\n", ret);
        return;
    }

    // 创建读任务
    task2.pfnTaskEntry = (TSK_ENTRY_FUNC)read_thread;
    task2.uwStackSize = 2048;
    task2.pcName = "read_thread";
    task2.usTaskPrio = 25;
    ret = LOS_TaskCreate(&thread_id2, &task2);
    if (ret != LOS_OK)
    {
        printf("Falied to create read_thread ret:0x%x\n", ret);
        return;
    }
}

APP_FEATURE_INIT(mutex_example);

四、代码逻辑解析

1. 共享资源

  • m_data:全局变量,被两个任务同时读写
  • m_mutex_id:互斥锁,用来保护 m_data

2. 写任务流程

  1. 申请锁 LOS_MuxPend
  2. 修改数据 m_data++
  3. 延时3秒 模拟占用资源
  4. 释放锁 LOS_MuxPost

3. 读任务流程

  1. 延时1秒后启动
  2. 申请锁
  3. 读取数据
  4. 延时1秒
  5. 释放锁

五、运行现象

写任务先拿到锁并占用3秒,期间读任务申请锁会阻塞等待;直到写任务释放锁后,读任务才能获取锁执行操作,全程保证同一时间只有一个任务操作共享变量 m_data

六、互斥锁使用规则

  1. 谁申请,谁释放,不能在其他任务里强行释放锁。
  2. 不允许重复嵌套申请同一把互斥锁,容易造成死锁。
  3. 只要是多任务共用的全局变量、外设、缓冲区,都要加锁保护。
  4. 锁内业务代码尽量精简,不要长时间占用锁,避免其他任务长期阻塞。

七、互斥锁与信号量核心区别

1. 核心定位

  • 互斥锁 :侧重资源排他占用,同一时刻只能有一个任务访问临界资源。
  • 信号量 :侧重任务同步、计数限流,可设置最大计数值,允许同时放行多个任务。

2. 关键差异点

  • 所有权:互斥锁必须谁加锁谁解锁;信号量任意任务都可以释放唤醒其他等待任务。
  • 初始名额:互斥锁固定只有1个名额;信号量可自定义最大计数数量。
  • 适用场景:互斥锁用于全局变量、串口等共享资源保护;信号量多用于线程唤醒、任务执行顺序同步、生产者消费者模型。

3. 通俗场景区分

  • 多任务争抢同一个共享变量、外设,防止数据错乱 → 用互斥锁
  • 一个线程控制另一个线程唤醒、调度多个线程按顺序执行 → 用信号量

八、总结

  1. 互斥锁相当于共享资源的专属门禁,保证同一时刻仅一个任务进入临界区。
  2. 使用流程固定:创建互斥锁 → 任务申请锁 → 访问共享资源 → 释放锁
  3. 互斥锁适合资源互斥保护,信号量适合任务同步,开发中根据业务场景合理选用即可。
相关推荐
大师兄66681 小时前
HarmonyOS 卡片 UI 三种玩法:普通卡片、动效卡片、Canvas 卡片
harmonyos·arkts·formkit·动效卡片·canvas卡片
特立独行的猫a6 小时前
鸿蒙 PC 命令行工具迁移实战 · 直播PPT
android·华为·harmonyos·vcpkg·三方库移植·鸿蒙pc
想你依然心痛6 小时前
HarmonyOS 6(API 23)实战:基于悬浮导航、沉浸光感与Face AR & Body AR的“灵犀智投“——PC端沉浸式AR量化交易分析工作台
华为·ar·harmonyos·悬浮导航·沉浸光感
特立独行的猫a6 小时前
鸿蒙 PC 三方库移植实战 · 直播课件(详细教案)
华为·harmonyos·移植·鸿蒙pc·opendesk
xmdy58668 小时前
Flutter+开源鸿蒙实战|企业级工具APP Day2 全局网络封装与 Dio 拦截器实战(鸿蒙兼容版)
flutter·开源·harmonyos
xmdy58668 小时前
Flutter+开源鸿蒙实战:企业级工具类APP开发教程(含第三方库适配)
flutter·开源·harmonyos
richard_yuu9 小时前
鸿蒙Stage模型实战|心晴驿站分层架构与隐私安全设计
安全·架构·harmonyos
Swift社区9 小时前
Flutter / React / ArkUI:在鸿蒙 PC 上怎么选?
flutter·react.js·harmonyos
leon_teacher9 小时前
HarmonyOS 6 鸿蒙APP应用实战:基于 ArkUI V2 打造儿童古诗学习宝 App 从 0 到 1
学习·华为·harmonyos