鸿蒙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. 写任务流程
- 申请锁
LOS_MuxPend - 修改数据
m_data++ - 延时3秒 模拟占用资源
- 释放锁
LOS_MuxPost
3. 读任务流程
- 延时1秒后启动
- 申请锁
- 读取数据
- 延时1秒
- 释放锁
五、运行现象

写任务先拿到锁并占用3秒,期间读任务申请锁会阻塞等待;直到写任务释放锁后,读任务才能获取锁执行操作,全程保证同一时间只有一个任务操作共享变量 m_data。
六、互斥锁使用规则
- 谁申请,谁释放,不能在其他任务里强行释放锁。
- 不允许重复嵌套申请同一把互斥锁,容易造成死锁。
- 只要是多任务共用的全局变量、外设、缓冲区,都要加锁保护。
- 锁内业务代码尽量精简,不要长时间占用锁,避免其他任务长期阻塞。
七、互斥锁与信号量核心区别
1. 核心定位
- 互斥锁 :侧重资源排他占用,同一时刻只能有一个任务访问临界资源。
- 信号量 :侧重任务同步、计数限流,可设置最大计数值,允许同时放行多个任务。
2. 关键差异点
- 所有权:互斥锁必须谁加锁谁解锁;信号量任意任务都可以释放唤醒其他等待任务。
- 初始名额:互斥锁固定只有1个名额;信号量可自定义最大计数数量。
- 适用场景:互斥锁用于全局变量、串口等共享资源保护;信号量多用于线程唤醒、任务执行顺序同步、生产者消费者模型。
3. 通俗场景区分
- 多任务争抢同一个共享变量、外设,防止数据错乱 → 用互斥锁。
- 一个线程控制另一个线程唤醒、调度多个线程按顺序执行 → 用信号量。
八、总结
- 互斥锁相当于共享资源的专属门禁,保证同一时刻仅一个任务进入临界区。
- 使用流程固定:创建互斥锁 → 任务申请锁 → 访问共享资源 → 释放锁。
- 互斥锁适合资源互斥保护,信号量适合任务同步,开发中根据业务场景合理选用即可。