LiteOS互斥锁

文章详细介绍了互斥锁的概念、作用以及在LiteOS操作系统中的实现和使用方法,包括互斥锁的优先级继承机制,防止优先级反转问题。文中还给出了互斥锁的创建、删除、获取和释放等函数,并提供了实际的代码示例,演示了如何在任务中使用互斥锁控制资源访问。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、基本概念

互斥锁又称互斥信号量,是一种特殊的二值信号量,常用于实现对临界资源的独占式处理。任务使用时,互斥锁处于闭锁状态,使用完毕,处于开锁状态。可以用于两个任务同时向串口发送等情况。

二、互斥锁的优先级继承机制

任务的优先级,在创建时已经指定,高优先级的任务可以打断低优先级的任务。低优先级的任务在使用互斥锁时,可能被高优先级的任务打断,那么暂时提高低优先级的任务的优先级,让它和高优先级的一样,避免了被抢占,使用完后,任务优先级恢复。

三、互斥锁的运行机制

(1)互斥锁保护的资源被占用时,无论何种优先级任务想要使用都会被阻塞

(2)正在使用互斥锁的任务1比阻塞中的任务2优先级低,暂时把1的优先级提升到2的

(3)当任务1使用完资源后会释放互斥锁,任务1的优先级恢复

(4)任务2此时可以获得互斥锁,并访问资源。

四、互斥锁的使用

4.1 互斥锁控制块
typedef struct
{
    UINT8           ucMuxStat;       /**< 互斥锁状态:OS_MUX_UNUSED或OS_MUX_USED  */
    UINT16          usMuxCount;      /**< 互斥锁持有次数 */
    UINT32          ucMuxID;         /**< 互斥锁ID*/
    LOS_DL_LIST     stMuxList;       /**< 互斥锁阻塞列表*/
    LOS_TASK_CB     *pstOwner;       /**< 任务控制块指针*/
    UINT16          usPriority;      /**< 记录互斥锁任务的初始优先级 */
} MUX_CB_S;
4.2 互斥锁错误代码

在los_mux.h文件中有定义

4.3 互斥锁函数

(1)互斥锁创建函数LOS_MuxCreate

(2)互斥锁删除函数LOS_MuxDelete

(3)互斥锁释放函数LOS_MuxPost

(4)互斥锁获取函数LOS_MuxPend

4.4 互斥锁使用注意事项

(1)两个任务不能获取同一个互斥锁

(2)不能在中断服务程序中使用

(3)获得后,尽快释放

(4)任务持有时,不允许再更改持有互斥锁的任务的优先级

(5)互斥锁和信号量的区别在于,互斥锁可以被已经持有互斥锁的任务重复获取,而不会死锁

五、互斥锁实验main文件

(1)模拟优先级翻转实验(使用二值信号量 )

创建了三个任务,分别为高优先级、中优先级、低优先级。程序依次执行高—中—低。串口打印流程如下:

高:获取二值信号量,释放

中:运行中

低:获取二值信号量,占用非常久,此时,高堵塞

中:运行中

中:运行中

低:释放二值信号量,高就绪,LOS_TaskYield函数将低任务释放CPU,将其移到相同优先级就绪队列的队尾

高:获取二值信号量,释放

中:运行中

高:获取二值信号量,释放

低:获取二值信号量,占用非常久

……

/* LiteOS 头文件 */
#include "los_sys.h"
#include "los_task.ph"
#include "los_queue.h"
#include "los_sem.h"
/* 板级外设头文件 */
#include "bsp_usart.h"
#include "bsp_led.h"
#include "bsp_key.h"
/* 定义任务句柄 */
UINT32 HighPriority_Task_Handle;
UINT32 MidPriority_Task_Handle;
UINT32 LowPriority_Task_Handle;

/*定义二值信号量的ID*/
UINT32 BinarySem_Handle;




/* 函数声明 */
static UINT32 AppTaskCreate(void);
static UINT32 Creat_HighPriority_Task(void);
static UINT32 Creat_MidPriority_Task(void);
static UINT32 Creat_LowPriority_Task(void);

static void  HighPriority_Task(void);
static void MidPriority_Task(void);
static void LowPriority_Task(void);
static void BSP_Init(void);



int main(void)
{    
    UINT32 uwRet = LOS_OK;  //定义一个任务创建的返回值,默认为创建成功
    
    /* 板载相关初始化 */
  BSP_Init();
    

    printf("串口打印出-Sucessful-表明实验创建成功\r\n");
    /* LiteOS 内核初始化 */
    uwRet = LOS_KernelInit();
    
  if (uwRet != LOS_OK)
  {
        printf("LiteOS 核心初始化失败!失败代码0x%X\n",uwRet);
        return LOS_NOK;
  }

    uwRet = AppTaskCreate();
    if (uwRet != LOS_OK)
  {
        printf("AppTaskCreate创建任务失败!失败代码0x%X\n",uwRet);
        return LOS_NOK;
  }

  /* 开启LiteOS任务调度 */
  LOS_Start();
    
    //正常情况下不会执行到这里
    while(1);
    
}

static UINT32 AppTaskCreate(void)
{
    /* 定义一个返回类型变量,初始化为LOS_OK */
    UINT32 uwRet = LOS_OK;
    
    /*创建一个二值信号量*/
    uwRet = LOS_BinarySemCreate(1,&BinarySem_Handle);
    if(uwRet!=LOS_OK)
    {
            printf("Test_Queue队列创建失败!失败代码0x%X\n",uwRet);
            return uwRet;
    }
    
    
    
    
    uwRet = Creat_HighPriority_Task();
  if (uwRet != LOS_OK)
  {
        printf("Receive_Task任务创建失败!失败代码0x%X\n",uwRet);
        return uwRet;
  }
    
    uwRet = Creat_MidPriority_Task();
  if (uwRet != LOS_OK)
  {
        printf("Send_Task任务创建失败!失败代码0x%X\n",uwRet);
        return uwRet;
  }
    
    uwRet = Creat_LowPriority_Task();
  if (uwRet != LOS_OK)
  {
        printf("Send_Task任务创建失败!失败代码0x%X\n",uwRet);
        return uwRet;
  }
    return LOS_OK;
}



static UINT32 Creat_HighPriority_Task()
{
    //定义一个创建任务的返回类型,初始化为创建成功的返回值
    UINT32 uwRet = LOS_OK;            
    
    //定义一个用于创建任务的参数结构体
    TSK_INIT_PARAM_S task_init_param;    

    task_init_param.usTaskPrio = 3;    /* 任务优先级,数值越小,优先级越高 */
    task_init_param.pcName = " HighPriority_Task";/* 任务名 */
    task_init_param.pfnTaskEntry = (TSK_ENTRY_FUNC) HighPriority_Task;/* 任务函数入口 */
    task_init_param.uwStackSize = 1024;        /* 堆栈大小 */

    uwRet = LOS_TaskCreate(& HighPriority_Task_Handle, &task_init_param);/* 创建任务 */
    return uwRet;
}


static UINT32 Creat_MidPriority_Task()
{
    // 定义一个创建任务的返回类型,初始化为创建成功的返回值
    UINT32 uwRet = LOS_OK;                
    TSK_INIT_PARAM_S task_init_param;

    task_init_param.usTaskPrio = 4;    /* 任务优先级,数值越小,优先级越高 */
    task_init_param.pcName = "MidPriority_Task";    /* 任务名*/
    task_init_param.pfnTaskEntry = (TSK_ENTRY_FUNC)MidPriority_Task;/* 任务函数入口 */
    task_init_param.uwStackSize = 1024;    /* 堆栈大小 */
    
    uwRet = LOS_TaskCreate(&MidPriority_Task_Handle, &task_init_param);/* 创建任务 */

    return uwRet;
}

static UINT32 Creat_LowPriority_Task()
{
    // 定义一个创建任务的返回类型,初始化为创建成功的返回值
    UINT32 uwRet = LOS_OK;                
    TSK_INIT_PARAM_S task_init_param;

    task_init_param.usTaskPrio = 5;    /* 任务优先级,数值越小,优先级越高 */
    task_init_param.pcName = "LowPriority_Task";    /* 任务名*/
    task_init_param.pfnTaskEntry = (TSK_ENTRY_FUNC)LowPriority_Task;/* 任务函数入口 */
    task_init_param.uwStackSize = 1024;    /* 堆栈大小 */
    
    uwRet = LOS_TaskCreate(&LowPriority_Task_Handle, &task_init_param);/* 创建任务 */

    return uwRet;
}


static void  HighPriority_Task(void)
{

    UINT32 uwRet = LOS_OK;
  /* 任务都是一个无限循环,不能返回 */
    while(1)
    {
        uwRet = LOS_SemPend(BinarySem_Handle, LOS_WAIT_FOREVER);
        //获取二值信号量(BinarySem_Handle,未获取到会一直等待
    if (uwRet == LOS_OK)
  {
        printf("高优先级任务运行中\n");
  }
        
        LED1_TOGGLE;
        LOS_SemPost(BinarySem_Handle);//释放二值信号量BinarySem_Handle
        LOS_TaskDelay(1000);
    }
}

static void MidPriority_Task(void)
{
    UINT32 uwRet = LOS_OK;
  /* 任务都是一个无限循环,不能返回 */
    while(1)
    {
            printf("中优先级任务运行中\n");
            LOS_TaskDelay(1000);
        
    }
}
static void LowPriority_Task(void)
{
    UINT32 uwRet = LOS_OK;
    
    static uint32_t i;
  /* 任务都是一个无限循环,不能返回 */
    while(1)
    {
        uwRet = LOS_SemPend(BinarySem_Handle, LOS_WAIT_FOREVER);
        //获取二值信号量(BinarySem_Handle,未获取到会一直等待
        if (uwRet == LOS_OK)
        {
            printf("低优先级任务运行中\n");
        }
        LED2_TOGGLE;
        
        for (i = 0;i<200000;i++){//模拟低优先级任务占用信号量
            
            LOS_TaskYield();//放弃剩余时间片,进行一次任务切换
        }
        printf("低优先任务释放信号量\r\n");
        
        LOS_SemPost(BinarySem_Handle);//释放二值信号量
        
        
            LOS_TaskDelay(1000);
        
    }
}
/*******************************************************************
  * @ 函数名  : BSP_Init
  * @ 功能说明: 板级外设初始化,所有板子上的初始化均可放在这个函数里面
  * @ 参数    :   
  * @ 返回值  : 无
  ******************************************************************/
static void BSP_Init(void)
{
    /*
     * STM32中断优先级分组为4,即4bit都用来表示抢占优先级,范围为:0~15
     * 优先级分组只需要分组一次即可,以后如果有其他的任务需要用到中断,
     * 都统一用这个优先级分组,千万不要再分组,切忌。
     */
    NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 );
    
    /* LED 初始化 */
    LED_GPIO_Config();

    /* 串口初始化    */
    USART_Config();
    /* KEY初始化 */
    Key_GPIO_Config();
}


/******************************END OF FILE*******************/

(2)互斥锁实验

低优先级任务运行时,中优先级任务无法抢占低优先级的任务

/* LiteOS 头文件 */
#include "los_sys.h"
#include "los_task.ph"
#include "los_queue.h"
#include "los_sem.h"
#include "los_mux.h"

/* 板级外设头文件 */
#include "bsp_usart.h"
#include "bsp_led.h"
#include "bsp_key.h"
/* 定义任务句柄 */
UINT32 HighPriority_Task_Handle;
UINT32 MidPriority_Task_Handle;
UINT32 LowPriority_Task_Handle;



/*定义互斥锁的ID变量*/
UINT32 Mutex_Handle;



/* 函数声明 */
static UINT32 AppTaskCreate(void);
static UINT32 Creat_HighPriority_Task(void);
static UINT32 Creat_MidPriority_Task(void);
static UINT32 Creat_LowPriority_Task(void);

static void  HighPriority_Task(void);
static void MidPriority_Task(void);
static void LowPriority_Task(void);
static void BSP_Init(void);



int main(void)
{    
    UINT32 uwRet = LOS_OK;  //定义一个任务创建的返回值,默认为创建成功
    
    /* 板载相关初始化 */
  BSP_Init();
    

    printf("串口打印出-Sucessful-表明实验创建成功\r\n");
    /* LiteOS 内核初始化 */
    uwRet = LOS_KernelInit();
    
  if (uwRet != LOS_OK)
  {
        printf("LiteOS 核心初始化失败!失败代码0x%X\n",uwRet);
        return LOS_NOK;
  }

    uwRet = AppTaskCreate();
    if (uwRet != LOS_OK)
  {
        printf("AppTaskCreate创建任务失败!失败代码0x%X\n",uwRet);
        return LOS_NOK;
  }

  /* 开启LiteOS任务调度 */
  LOS_Start();
    
    //正常情况下不会执行到这里
    while(1);
    
}

static UINT32 AppTaskCreate(void)
{
    /* 定义一个返回类型变量,初始化为LOS_OK */
    UINT32 uwRet = LOS_OK;
    
    /*创建一个互斥锁*/
    uwRet = LOS_MuxCreate(&Mutex_Handle);
    if(uwRet!=LOS_OK)
    {
            printf("Mutex创建失败!失败代码0x%X\n",uwRet);
            return uwRet;
    }
    
    
    
    
    uwRet = Creat_HighPriority_Task();
  if (uwRet != LOS_OK)
  {
        printf("Receive_Task任务创建失败!失败代码0x%X\n",uwRet);
        return uwRet;
  }
    
    uwRet = Creat_MidPriority_Task();
  if (uwRet != LOS_OK)
  {
        printf("Send_Task任务创建失败!失败代码0x%X\n",uwRet);
        return uwRet;
  }
    
    uwRet = Creat_LowPriority_Task();
  if (uwRet != LOS_OK)
  {
        printf("Send_Task任务创建失败!失败代码0x%X\n",uwRet);
        return uwRet;
  }
    return LOS_OK;
}



static UINT32 Creat_HighPriority_Task()
{
    //定义一个创建任务的返回类型,初始化为创建成功的返回值
    UINT32 uwRet = LOS_OK;            
    
    //定义一个用于创建任务的参数结构体
    TSK_INIT_PARAM_S task_init_param;    

    task_init_param.usTaskPrio = 3;    /* 任务优先级,数值越小,优先级越高 */
    task_init_param.pcName = " HighPriority_Task";/* 任务名 */
    task_init_param.pfnTaskEntry = (TSK_ENTRY_FUNC) HighPriority_Task;/* 任务函数入口 */
    task_init_param.uwStackSize = 1024;        /* 堆栈大小 */

    uwRet = LOS_TaskCreate(& HighPriority_Task_Handle, &task_init_param);/* 创建任务 */
    return uwRet;
}


static UINT32 Creat_MidPriority_Task()
{
    // 定义一个创建任务的返回类型,初始化为创建成功的返回值
    UINT32 uwRet = LOS_OK;                
    TSK_INIT_PARAM_S task_init_param;

    task_init_param.usTaskPrio = 4;    /* 任务优先级,数值越小,优先级越高 */
    task_init_param.pcName = "MidPriority_Task";    /* 任务名*/
    task_init_param.pfnTaskEntry = (TSK_ENTRY_FUNC)MidPriority_Task;/* 任务函数入口 */
    task_init_param.uwStackSize = 1024;    /* 堆栈大小 */
    
    uwRet = LOS_TaskCreate(&MidPriority_Task_Handle, &task_init_param);/* 创建任务 */

    return uwRet;
}

static UINT32 Creat_LowPriority_Task()
{
    // 定义一个创建任务的返回类型,初始化为创建成功的返回值
    UINT32 uwRet = LOS_OK;                
    TSK_INIT_PARAM_S task_init_param;

    task_init_param.usTaskPrio = 5;    /* 任务优先级,数值越小,优先级越高 */
    task_init_param.pcName = "LowPriority_Task";    /* 任务名*/
    task_init_param.pfnTaskEntry = (TSK_ENTRY_FUNC)LowPriority_Task;/* 任务函数入口 */
    task_init_param.uwStackSize = 1024;    /* 堆栈大小 */
    
    uwRet = LOS_TaskCreate(&LowPriority_Task_Handle, &task_init_param);/* 创建任务 */

    return uwRet;
}


static void  HighPriority_Task(void)
{

    UINT32 uwRet = LOS_OK;
  /* 任务都是一个无限循环,不能返回 */
    while(1)
    {
        uwRet = LOS_MuxPend(Mutex_Handle, LOS_WAIT_FOREVER);
        //获取Mutex,未获取到会一直等待
    if (uwRet == LOS_OK)
  {
        printf("高优先级任务运行中\n");
  }
        
        LED1_TOGGLE;
        LOS_MuxPost(Mutex_Handle);//释放
        LOS_TaskDelay(1000);
    }
}

static void MidPriority_Task(void)
{
    UINT32 uwRet = LOS_OK;
  /* 任务都是一个无限循环,不能返回 */
    while(1)
    {
            printf("中优先级任务运行中\n");
            LOS_TaskDelay(1000);
        
    }
}
static void LowPriority_Task(void)
{
    UINT32 uwRet = LOS_OK;
    
    static uint32_t i;
  /* 任务都是一个无限循环,不能返回 */
    while(1)
    {
        uwRet = LOS_MuxPend(Mutex_Handle, LOS_WAIT_FOREVER);
        //获取Mutex,未获取到会一直等待
        if (uwRet == LOS_OK)
        {
            printf("低优先级任务运行中\n");
        }
        LED2_TOGGLE;
        
        for (i = 0;i<200000;i++){//模拟低优先级任务占用信号量
            
            LOS_TaskYield();//放弃剩余时间片,进行一次任务切换
        }
        printf("低优先任务释放互斥锁\r\n");
        
        LOS_MuxPost(Mutex_Handle);//释放互斥锁
        
        
            LOS_TaskDelay(1000);
        
    }
}
/*******************************************************************
  * @ 函数名  : BSP_Init
  * @ 功能说明: 板级外设初始化,所有板子上的初始化均可放在这个函数里面
  * @ 参数    :   
  * @ 返回值  : 无
  ******************************************************************/
static void BSP_Init(void)
{
    /*
     * STM32中断优先级分组为4,即4bit都用来表示抢占优先级,范围为:0~15
     * 优先级分组只需要分组一次即可,以后如果有其他的任务需要用到中断,
     * 都统一用这个优先级分组,千万不要再分组,切忌。
     */
    NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 );
    
    /* LED 初始化 */
    LED_GPIO_Config();

    /* 串口初始化    */
    USART_Config();
    /* KEY初始化 */
    Key_GPIO_Config();
}


/******************************END OF FILE*******************/

内容概要:本文详细介绍了LiteOS互斥锁在嵌入式开发中的应用,旨在帮助开发者理解和掌握互斥锁的工作原理及其重要性。LiteOS是华为开发的一款轻量级操作系统,专为物联网设计,具有快速启动、节能等特性。互斥锁作为一种同步机制,确保多任务环境中只有一个任务能访问共享资源,防止数据冲突。文章深入剖析了互斥锁的基本概念、优先级继承机制以及运作流程,包括创建、获取、释放和删除互斥锁的具体步骤。文中还展示了互斥锁在智能家居系统和工业控制系统中的实际应用场景,并强调了使用互斥锁时的注意事项,如避免重复加锁、不在中断服务程序中使用互斥锁、及时释放锁等。最后,文章讨论了死锁和优先级反转问题的原因及解决方案。 适合人群:对嵌入式开发有兴趣的工程师,尤其是从事物联网、智能家居、工业控制等领域开发的技术人员。 使用场景及目标:①帮助开发者理解LiteOS互斥锁的工作原理及其在多任务环境中的重要性;②指导开发者如何在实际项目中正确使用互斥锁,避免数据冲突和优先级翻转问题;③提供具体的代码示例和应用场景分析,便于开发者在实际开发中应用所学知识。 阅读建议:本文内容详尽,涵盖了从理论到实践的各个方面。建议读者在阅读过程中结合代码示例进行实践操作,理解互斥锁的具体实现和使用方法。同时,注意互斥锁使用的注意事项,避免常见错误,确保系统稳定性和可靠性。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值