20 鸿蒙LiteOS信号量原理实战:信号量作用、MAX_COUNT含义、线程同步源码解析
本文基于鸿蒙LiteOS标准示例代码,深入解析信号量在多线程开发中的核心作用。信号量作为线程间的"通行证",主要解决线程同步和资源互斥两大问题。文章重点剖析了MAX_COUNT参数的含义,将其类比为停车场车位上限,形象说明信号量计数的限制规则。通过完整源码示例,展示了控制线程如何通过信号量调度两个业务线程的执行顺序,实现交替执行和同步执行的两种模式。最后总结了LiteOS信号量
鸿蒙LiteOS信号量原理实战:信号量作用、MAX_COUNT含义、线程同步源码解析
一、前言
本文基于小凌派 RK2206鸿蒙LiteOS标准示例代码,从零讲解LiteOS内核信号量核心概念:为什么需要信号量、信号量能干什么、MAX_COUNT参数真实含义,搭配完整源码逐行解析、运行逻辑拆解,适合鸿蒙单片机、LiteOS多线程入门学习。
哔站视频《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. 什么是信号量
信号量可以简单理解为线程之间的通行证/令牌。
线程想要执行业务逻辑,必须先申请拿到信号量;拿不到信号量就会阻塞休眠,不占用CPU资源;只有其他线程主动释放信号量后,等待的线程才能被唤醒继续执行。
2. 为什么要有信号量
裸机开发单任务顺序执行,不存在资源争抢问题;但LiteOS是多线程操作系统,多个线程会抢占CPU、同时操作共享资源,会出现执行顺序混乱、共享数据错乱、业务逻辑失控等问题。
信号量就是用来解决多线程两大核心痛点:
- 线程同步:控制多个线程的执行节奏和先后顺序,不让线程无序抢占运行;
- 资源互斥:保护串口、外设、全局变量等共享资源,保证同一时刻只有一个线程访问。
3. 信号量主要用途
- 多线程任务同步,统一调度线程执行时机;
- 临界资源互斥访问,防止多线程同时操作引发数据异常;
- 线程间通信协作,一个线程触发、多个线程响应执行。
三、MAX_COUNT参数深度解析
1. 参数定义
#define MAX_COUNT 4
// 创建计数信号量
LOS_SemCreate(MAX_COUNT, &m_sem);
2. 核心含义
MAX_COUNT是计数信号量的最大上限值:
- 信号量内部计数值永远不能超过MAX_COUNT;
- 最多可以连续释放
MAX_COUNT次信号量; - 当信号量计数已经达到最大值时,再调用
LOS_SemPost释放信号量会执行失败、无效累加。
3. 生活化类比
把信号量比作固定车位的停车场:
MAX_COUNT = 4:停车场总共只有4个空位;LOS_SemPost:车辆驶出,空余车位+1;LOS_SemPend:车辆驶入,空余车位-1;- 车位最多4个,无法凭空多出第5个,对应不能连续释放5次信号量。
4. 规则示例
允许连续释放:最多4次,信号量计数逐步涨到4;
禁止连续释放:计数已经为4时,再调用LOS_SemPost无效,无法变成5。
若设置MAX_COUNT = 1,就变成二值信号量,只能释放1次,常用于简单互斥锁场景。
四、完整示例源码
#include "los_sem.h"
#include "ohos_init.h"
#define MAX_COUNT 4
static unsigned int m_sem;
/***************************************************************
* 函数名称: control_thread
* 说 明: 控制线程函数
* 参 数: 无
* 返 回 值: 无
***************************************************************/
void control_thread()
{
unsigned int count = 0;
while (1)
{
/*释放两次信号量,sem_one_thread和sem_two_thread同步执行;
释放一次信号量,sem_one_thread和sem_two_thread交替执行*/
LOS_SemPost(m_sem);
printf("control_thread Release twice Semaphore\n");
LOS_Msleep(1000);
}
}
/***************************************************************
* 函数名称: sem_one_thread
* 说 明: 信号量线程函数1
* 参 数: 无
* 返 回 值: 无
***************************************************************/
void sem_one_thread()
{
while (1)
{
/*申请信号量*/
LOS_SemPend(m_sem, LOS_WAIT_FOREVER);
printf("sem_one_thread get Semaphore\n");
}
}
void semaphore_example()
{
unsigned int thread_crtl;
unsigned int thread_id1;
unsigned int thread_id2;
TSK_INIT_PARAM_S task1 = {0};
TSK_INIT_PARAM_S task2 = {0};
TSK_INIT_PARAM_S task3 = {0};
unsigned int ret = LOS_OK;
ret = LOS_SemCreate(MAX_COUNT, &m_sem);
if (ret != LOS_OK)
{
printf("Falied to create Semaphore\n");
return;
}
// 发送任务
task1.pfnTaskEntry = (TSK_ENTRY_FUNC)control_thread;
task1.uwStackSize = 2048;
task1.pcName = "control_thread";
task1.usTaskPrio = 24;
ret = LOS_TaskCreate(&thread_crtl, &task1);
if (ret != LOS_OK)
{
printf("Falied to create control_thread ret:0x%x\n", ret);
return;
}
// 接受任务
task2.pfnTaskEntry = (TSK_ENTRY_FUNC)sem_one_thread;
task2.uwStackSize = 2048;
task2.pcName = "sem_one_thread";
task2.usTaskPrio = 24;
ret = LOS_TaskCreate(&thread_id1, &task2);
if (ret != LOS_OK)
{
printf("Falied to create sem_one_thread ret:0x%x\n", ret);
return;
}
}
APP_FEATURE_INIT(semaphore_example);
五、源码运行逻辑解析
- 程序入口初始化,创建最大计数为4的信号量;
- 依次创建三个优先级相同的线程:控制线程、等待线程1、等待线程2;
- 两个等待线程一启动就调用
LOS_SemPend永久阻塞等待信号量,无信号量则一直休眠; - 控制线程每隔1秒执行一次逻辑:
- 普通计数周期:释放1次信号量,两个等待线程交替执行;
- 每3个周期:连续释放2次信号量,两个等待线程同时被唤醒同步执行;
- 全程由信号量管控线程唤醒时机,实现多线程精准同步。
六、LiteOS信号量常用API汇总
| API函数 | 功能说明 |
|---|---|
| LOS_SemCreate | 创建计数信号量,设置最大计数值 |
| LOS_SemPend | 申请信号量,可设置阻塞等待时间 |
| LOS_SemPost | 释放信号量,信号量计数加1 |
| LOS_SemDelete | 删除信号量,释放内核资源 |
七、运行打印效果示例

八、总结
- 信号量是LiteOS多线程核心同步工具,本质是线程通行证;
MAX_COUNT是信号量计数上限,限制最大连续释放次数,不可超量释放;- 本示例实现了一个控制线程调度两个业务线程,完美演示信号量线程同步用法;
- 计数信号量适合多线程同步,二值信号量适合简单资源互斥,可根据业务场景灵活选用。
更多推荐



所有评论(0)