此笔记由个人整理
华为IOT LiteOS开发实战营
第三天
一、简介
- 互斥锁又称互斥型信号量,是一种特殊的二型信号量,用于实现对共享资源的独占式处理
- 任意时刻互斥锁的状态,只有两种:开锁或闭锁
- 当有任务持有时,互斥锁处于闭锁状态,这个任务获得该互斥锁的所有权
- 当该任务释放时,该互斥锁被开锁,任务失去该互斥锁的所有权
- 当一个任务持有互斥锁时,其他任务将不能再对该互斥锁进行开锁或持有
- 多任务环境下往往存在多个任务竞争统一共享资源的应用场景,互斥锁可被用于对共享资源的保护,从而实现独占式访问。另外互斥锁可以解决信号量存在的优先级翻转问题
- LiteOS提供的互斥锁具有如下特点:通过优先级继承算法解决优先级翻转问题
二、运作原理
- 多任务环境下会存在多个任务访问同一公共资源的场景,而有些公共资源是非共享的,需要任务进行独占式处理,互斥锁怎么怎样来避免这样的冲突呢?
- 用互斥锁处理非共享资源的同步访问时,如果有任务访问该资源,则互斥锁倍加锁状态,此时其他任务如果想访问这个公共资源则会被阻塞。直到互斥锁被持有的该任务释放后,其他任务才能重新访问该公共资源,此时,互斥锁再次上锁,如此确保同一时刻只有一个任务正在访问该公共资源,保证了公共资源操作的完整性。
三、使用场景及开发流程
使用场景
- 互斥锁可以提供任务之间的互斥机制,用于防止两个任务在同一时刻访问相同的共享资源
- 互斥锁还可以被用于防止多任务同步时,造成的优先级翻转问题
1、两个任务不能对同一把互斥锁加锁。如果某任务对已被持有的互斥锁加锁,则该任务会被挂起,直到持有该锁的任务对互斥锁解锁,才能执行对这把互斥锁的加锁操作
2、互斥锁不能在中断服务程序中使用
3、尽量避免任务的长时间阻塞,因此在获得互斥锁之后,应该尽快释放互斥锁
4、有互斥锁的过程中,不得再调用优先级调整等接口函数更改持有互斥锁任务的优先级
开发流程
- 创建->申请->释放->删除
四、操作系统抽象层
osal_mutex_create(osal_mutex_t *mutex)
osal_mutex_del(osal_mutex_t mutex)
osal_mutex_lock(osal_mutex_t mutex)
osal_mutex_unlock(osal_mutex_t mutex)
五、代码实践
- 创建工程,选择互斥锁案例
基础实验
- 代码
#include <osal.h>
#define USER_TASK1_PRI 12//优先级低
#define USER_TASK2_PRI 11//优先级高
uint32_t public_value = 0;//公共值
osal_mutex_t public_value_mutex; //互斥锁索引id地址
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;//公共值自加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)//如果公共值大于100则退出程序
break;
}
}
return 0;
}
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; //公共值自加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)//公共值大于90则退出程序
break;
osal_task_sleep(10);
}
}
return 0;
}
int standard_app_demo_main()//主函数
{
osal_mutex_create(&public_value_mutex);//创建互斥锁
osal_task_create("user_task1",user_task1_entry,NULL,0x400,NULL,USER_TASK1_PRI);//任务一
osal_task_create("user_task2",user_task2_entry,NULL,0x400,NULL,USER_TASK2_PRI);//任务二
return 0;
}
- 结果:task1先创建,但是优先级较低,所以后创建的task2抢占执行,task2获取到互斥锁,对共享资源进行操作,操作完毕解锁,然后主动挂起,task1获取到互斥锁,对共享资源进行另一个操作,操作完毕解锁,在task1操作的时候,task2早已挂起完毕,但是获取不到互斥锁,所以挂起等待,在task1解锁后,阻塞的task2被唤醒开始执行。
扩展实验
-
1、使用返回值检查函数运行状态
-
2、加入for循环延时
-
3、删除互斥锁产生的现象
-
代码
#include <osal.h>
#define USER_TASK1_PRI 12//优先级低
#define USER_TASK2_PRI 11//优先级高
uint32_t public_value = 0;//公共值
osal_mutex_t public_value_mutex; //互斥锁索引id地址
static int user_task1_entry()//任务一
{
while(1)
{
if(true == osal_mutex_lock(public_value_mutex))//判断得到互斥锁
{
printf("\r\ntask1: lock a mutex OK.\r\n");
public_value += 10;//公共值自加10
printf("task1: public_value = %ld.\r\n", public_value);
printf("task1: unlock a mutex.\r\n\r\n");
for(uint32_t i=0;i<5000;i++)
for(uint32_t j=0;j<5000;j++);
if(true==osal_mutex_unlock(public_value_mutex))
{
printf("task1: unlock a mutex OK.\r\n\r\n");
}
else
{
printf("task1: unlock a mutex ERROR.\r\n\r\n");
}
if(public_value > 45)
{
if(true==osal_mutex_del(public_value_mutex))
{
printf("task1: del a mutex OK.\r\n\r\n");
}
else
{
printf("task1: del a mutex ERROR.\r\n\r\n");
}
}
if(public_value > 100)//如果公共值大于100则退出程序
break;
}
else
{
printf("\r\ntask1: lock a mutex ERROR.\r\n");
osal_task_sleep(1000);
return 0;
}
}
return 0;
}
static int user_task2_entry()//任务二
{
while (1)
{
if(true == osal_mutex_lock(public_value_mutex))//判断得到互斥锁
{
printf("\r\ntask2: lock a mutex OK.\r\n");
public_value += 5; //公共值自加5
printf("task2: public_value = %ld.\r\n", public_value);
for(uint32_t i=0;i<3000;i++)
for(uint32_t j=0;j<3000;j++);
if(true==osal_mutex_unlock(public_value_mutex))
{
printf("task2: unlock a mutex OK.\r\n\r\n");
}
else
{
printf("task2: unlock a mutex ERROR.\r\n\r\n");
}
if(public_value > 90)//公共值大于90则退出程序
break;
osal_task_sleep(10);
}
else
{
printf("\r\ntask2: lock a mutex ERROR.\r\n");
osal_task_sleep(1000);
return 0;
}
}
return 0;
}
int standard_app_demo_main()//主函数
{
osal_mutex_create(&public_value_mutex);//创建互斥锁
osal_task_create("user_task1",user_task1_entry,NULL,0x400,NULL,USER_TASK1_PRI);//任务一
osal_task_create("user_task2",user_task2_entry,NULL,0x400,NULL,USER_TASK2_PRI);//任务二
return 0;
}