小熊派华为物联网操作系统LiteOS内核教程05-互斥锁

news/2024/10/18 1:36:10/

1. LiteOS的互斥锁

1.1. 互斥锁

在多任务环境下,往往存在多个任务竞争同一共享资源的应用场景,互斥锁可被用于对共享资源的保护从而实现独占式访问。互斥锁(mutex)又称互斥型信号量,是一种特殊的二值信号量,用于实现对共享资源的独占式处理。另外,Huawei LiteOS提供的互斥锁通过优先级继承算法,解决了优先级翻转问题。

1.2. 互斥锁的使用方式

多任务环境下会存在多个任务访问同一公共资源的场景,而有些公共资源是非共享的,需要任务进行独占式处理

互斥锁怎样来避免这种冲突呢?

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

当有任务持有时,互斥锁处于闭锁状态,这个任务获得该互斥锁的所有权。当该任务释放它时,该互斥锁被开锁,任务失去该互斥锁的所有权。当一个任务持有互斥锁时,其他任务将不能再对该互斥锁进行开锁或持有。

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

1.3. 互斥锁的使用场景

互斥锁可以提供任务之间的互斥机制,用来防止两个任务在同一时刻访问相同的共享资源。

除此之外,互斥锁还可以被用于防止多任务同步时造成优先级翻转的问题。

2. 互斥锁API

Huawei LiteOS 系统中的互斥锁模块为用户提供创建/删除互斥锁、获取/释放互斥锁的功能。

Huawei LiteOS 系统中提供的互斥锁 API 都是以 LOS 开头,但是这些 API 使用起来比较复杂,所以本文中我们使用 Huawei IoT Link SDK 提供的统一API接口进行实验,这些接口底层已经使用 LiteOS 提供的API实现,对用户而言更为简洁,API列表如下:

osal的api接口声明在 中,使用相关的接口需要包含该头文件,关于函数的详细参数请参考该头文件的声明。

相关的接口定义在osal.c中,基于LiteOS的接口实现在 liteos_imp.c文件中:

接口名
功能描述
osalmutexcreate创建互斥锁
osalmutexdel
删除互斥锁
osalmutexlock
获取互斥锁(上锁)
osalmutexunlock释放互斥锁(解锁)

2.1. osalmutexcreate

osal_mutex_create接口用于创建一个互斥锁,其接口原型如下:

bool_t  osal_mutex_create(osal_mutex_t *mutex)
{bool_t ret = false;if((NULL != s_os_cb) &&(NULL != s_os_cb->ops) &&(NULL != s_os_cb->ops->mutex_create)){ret = s_os_cb->ops->mutex_create(mutex);}return ret;}

该接口的参数说明如下表:

参数描述
mutex互斥锁索引ID的地址
返回值false - 创建失败
返回值true - 创建成功

2.2. osalmutexdel

osal_mutex_del接口用于删除一个互斥锁,其接口原型如下:

bool_t  osal_mutex_del(osal_mutex_t mutex)
{bool_t ret = false;if((NULL != s_os_cb) &&(NULL != s_os_cb->ops) &&(NULL != s_os_cb->ops->mutex_del)){ret = s_os_cb->ops->mutex_del(mutex);}return ret;}

该接口的参数说明如下表:

参数描述
mutex互斥锁索引ID
返回值false - 删除失败
返回值true - 删除成功

2.3. osalmutexlock

osal_mutex_lock接口用于获取一个互斥锁,其接口原型如下:

bool_t  osal_mutex_lock(osal_mutex_t mutex)
{bool_t ret = false;if((NULL != s_os_cb) &&(NULL != s_os_cb->ops) &&(NULL != s_os_cb->ops->mutex_lock)){ret = s_os_cb->ops->mutex_lock(mutex);}return ret;}

参数描述
mutex互斥锁索引ID
返回值false - 申请失败
返回值true - 申请成功

2.4. osalmutexunlock

osal_mutex_unlock接口用于释放一个互斥锁,如果有任务阻塞等待该互斥锁,则唤醒最早被阻塞的任务,该任务进入就绪态,并进行调度。

其接口原型如下:

bool_t  osal_mutex_unlock(osal_mutex_t mutex)
{bool_t ret = false;if((NULL != s_os_cb) &&(NULL != s_os_cb->ops) &&(NULL != s_os_cb->ops->mutex_unlock)){ret = s_os_cb->ops->mutex_unlock(mutex);}return ret;
}

该接口的参数说明如下表:

参数描述
mutex互斥锁索引ID
返回值false - 释放失败
返回值true - 释放成功

3. 动手实验 —— 使用互斥锁进行资源保护

实验内容

本实验中将创建两个任务,一个低优先级任务task1,一个高优先级任务task2,两个任务之间依次对共享资源上锁、操作、解锁,在串口终端中观察两个任务的运行情况。

实验代码

首先打开上一篇使用的 HelloWorld 工程,基于此工程进行实验。

在Demo文件夹右击,新建文件夹osal_kernel_demo用于存放内核的实验文件(如果已有请忽略这一步)。

接下来在此文件夹中新建一个实验文件 osal_mutex_demo.c,开始编写代码:

/* 使用osal接口需要包含该头文件 */
#include <osal.h>/* 任务优先级宏定义(shell任务的优先级为10) */
#define USER_TASK1_PRI  12  //低优先级
#define USER_TASK2_PRI  11  //高优先级/* 共享资源 */
uint32_t public_value = 0;/* 互斥锁索引ID */
osal_mutex_t public_value_mutex;/* 任务task1入口函数 */
static int user_task1_entry()
{while(1){/* 尝试获取互斥锁 */if(true == osal_mutex_lock(public_value_mutex)){/* 获取到互斥锁,对共享资源进行操作 */printf("\r\ntask1: lock a mutex.\r\n");public_value  = 10;printf("task1: public_value = %ld.\r\n", public_value);/* 对共享资源操作完毕,释放互斥锁 */printf("task1: unlock a mutex.\r\n\r\n");osal_mutex_unlock(public_value_mutex);/* 满足条件则结束任务 */if(public_value > 100)break;}}/* while(1)会执行结束,所以需要返回值 */return 0;
}/* 任务task2入口函数 */
static int user_task2_entry()
{while (1){/* 尝试获取互斥锁 */if(true == osal_mutex_lock(public_value_mutex)){/* 获取到互斥锁,对共享资源进行操作 */printf("\r\ntask2: lock a mutex.\r\n");public_value  = 5; printf("task2: public_value = %ld.\r\n", public_value);/* 对共享资源操作完毕,释放互斥锁 */printf("task2: unlock a mutex.\r\n\r\n");osal_mutex_unlock(public_value_mutex);/* 满足条件则结束任务 */if(public_value > 90)break;/* 优先级较高,需要挂起一下,让task1获取到互斥锁,否则task2再次上锁,形成死锁 */osal_task_sleep(10);}}/* while(1)会执行结束,所以需要返回值 */return 0;
}/* 标准demo启动函数,函数名不要修改,否则会影响下一步实验 */
int standard_app_demo_main()
{/* 创建互斥锁public_value_mutex */osal_mutex_create(&public_value_mutex);/* 创建任务task1 */osal_task_create("user_task1",user_task1_entry,NULL,0x400,NULL,USER_TASK1_PRI);/* 创建任务task2 */osal_task_create("user_task2",user_task2_entry,NULL,0x400,NULL,USER_TASK2_PRI);return 0;
}

编写完成之后,要将我们编写的 osalmutexdemo.c文件添加到makefile中,加入整个工程的编译:

这里有个较为简单的方法,直接修改Demo文件夹下的user_demo.mk配置文件,添加如下代码:

#example for osal_mutex_demo
ifeq ($(CONFIG_USER_DEMO), "osal_mutex_demo")    user_demo_src  = ${wildcard $(TOP_DIR)/targets/STM32L431_BearPi/Demos/osal_kernel_demo/osal_mutex_demo.c}
endif

添加位置如图:

这段代码的意思是:

如果 CONFIGUSERDEMO 宏定义的值是osal_mutex_demo,则将osal_mutex_demo.c文件加入到makefile中进行编译。

那么,如何配置 CONFIGUSERDEMO 宏定义呢?在工程根目录下的.sdkconfig文件中的末尾即可配置:

因为我们修改了mk配置文件,所以点击重新编译按钮进行编译,编译完成后点击下载按钮烧录程序。

实验现象

程序烧录之后,即可看到程序已经开始运行,在串口终端中可看到实验的输出内容:

linkmain:V1.2.1 AT 11:30:59 ON Nov 28 2019WELCOME TO IOT_LINK SHELLLiteOS:/>
task2: lock a mutex.
task2: public_value = 5.
task2: unlock a mutex.task1: lock a mutex.
task1: public_value = 15.
task1: unlock a mutex.task1: lock a mutex.
task1: public_value = 25.
task1: unlock a mutex.task2: lock a mutex.
task2: public_value = 30.
task2: unlock a mutex.task1: lock a mutex.
task1: public_value = 40.
task1: unlock a mutex.task1: lock a mutex.
task1: public_value = 50.
task1: unlock a mutex.task2: lock a mutex.
task2: public_value = 55.
task2: unlock a mutex.task1: lock a mutex.
task1: public_value = 65.
task1: unlock a mutex.task1: lock a mutex.
task1: public_value = 75.
task1: unlock a mutex.task2: lock a mutex.
task2: public_value = 80.
task2: unlock a mutex.task1: lock a mutex.
task1: public_value = 90.
task1: unlock a mutex.task1: lock a mutex.
task1: public_value = 100.
task1: unlock a mutex.task2: lock a mutex.
task2: public_value = 105.
task2: unlock a mutex.

可以看到,系统启动后,首先打印版本号,串口shell的优先级为10,最先打印shell信息,接下来task1先创建,但是优先级较低,所以后创建的task2抢占执行,task2获取到互斥锁,对共享资源进行操作,操作完毕解锁,然后主动挂起,task1获取到互斥锁,对共享资源进行另一个操作,操作完毕解锁,在task1操作的时候,task2早已挂起完毕,但是获取不到互斥锁,所以挂起等待,在task1解锁后,堵塞的task2被唤醒开始执行。

小熊派开源社区,专注于IoT、AI、5G等前沿技术分享,关注“小熊派开源社区”微信公众号,获取更多资料教程。


http://www.ppmy.cn/news/860374.html

相关文章

小熊派HarmonyOS 鸿蒙·季 开发教程学习笔记(01)

小熊派HarmonyOS 鸿蒙季 开发教程学习笔记&#xff08;01&#xff09; BearPi-HM Nano开发板介绍 BearPi-HM Nano开发板功能介绍 BearPi-HM Nano开发板是一块专门为鸿蒙OS设计的HarmonyOs开发板&#xff0c;板载高度集成的2.4GHz WLAN SoC芯片Hi3861&#xff0c;并板载NFC电…

小熊派HarmonyOS 鸿蒙开发板-BearPi-HM Nano 十分钟上手教程

一、准备工作 准备一台电脑&#xff1a; 无具体要求&#xff0c;家用即可&#xff0c;Windows系统 二、开始下载 下载官方提供镜像 下载地址&#xff08;百度云&#xff09;&#xff1a;https://pan.baidu.com/s/1T0Tcl3y48C1p5L6y-6HJNg 提取码&#xff1a;eusr 下载HiBurn …

华为小熊派开发记录STM32+MPU6050+WIFI8266

华为小熊派开发记录STM32MPU6050WIFI8266 前言STM32CubeMXMDKLiteOSMPU6050WIFI8266华为云使用其它 前言 忽悠下参加了物联网开发比赛&#xff0c;用了华为小熊派开发板&#xff0c;之前有过TI的开发经历&#xff0c;这次不知道为什么脑热选了华为&#xff0c;总之整个过程走下…

vue使用html2canvas实现一键截图并赋值到剪贴板,只截取当前显示器上可视的内容

使用html2canvas 和 clipboard API实现整页截图并填充至剪切板。 访问剪切板的api只支持在https或者本地localhost上使用&#xff0c;如果是http&#xff0c;则无法使用 首先需要从npm安装html2canvas npm install html2canvas然后在代码中导入这个包&#xff1a; import ht…

HarmonyOS + linkboy + 小熊派,能擦出怎样的火花?

关注「嵌入式大杂烩」&#xff0c;选择「星标公众号」一起进步&#xff01; linkboy简介 linkboy是一门面向物联网、边缘计算、工业控制等领域的自研编程语言。linkboy官网地址&#xff1a; ❝ http://www.linkboy.cc/index.html ❞ &#xff08;相关资料需要到官网下载&#x…

华为云MVP熊保松谈物联网开发:华为云IoT是首选,小熊派是神器

摘要&#xff1a;在AI、5G的技术驱动下&#xff0c;物联网行业的发展愈加如火如荼&#xff0c;开发者在技术的快速更迭间&#xff0c;也得乘风破浪跟上新技术的节奏。 在AI、5G的技术驱动下&#xff0c;物联网行业的发展愈加如火如荼&#xff0c;开发者在技术的快速更迭间&…

训练速度提升300倍,Niantic最新VPS视觉定位方案亮相

近年来在谷歌、Niantic等推动下&#xff0c;视觉定位对于AR应用的重要性越来越明显&#xff0c;尤其是在室内导航场景&#xff0c;定位精度可超越传统GPS方案。为了进一步提升视觉定位、深度视觉地图构建的准确性&#xff0c;Niantic Labs在CVPR 2023期间公布了ACE方案&#xf…

10大主流压力/负载/性能测试工具推荐

在移动应用和Web服务正式发布之前&#xff0c;除了进行必要的功能测试和安全测试&#xff0c;为了保证互联网产品的服务交付质量&#xff0c;往往还需要做压力/负载/性能测试。然而很多传统企业在试水互联网的过程中&#xff0c;往往由于资源或产品迭代速度等原因忽视了这一块工…