LiteOS 互斥锁机制

Posted 易飞澈信息科技

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LiteOS 互斥锁机制相关的知识,希望对你有一定的参考价值。

LiteOS 互斥锁机制

基本概念


互斥锁又称互斥型信号量,是一种特殊的二值性信号量,用于实现对共享资源的独占式处理


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


多任务环境下往往存在多个任务竞争同一共享资源的应用场景,互斥锁可被用于对共享资源的保护,从而实现独占式访问。另外,互斥锁可以解决信号量存在的优先级翻转问题。


互斥锁特点:


通过优先级继承算法,解决优先级翻转问题


◆ ◆ ◆  ◆ 


接下来看下互斥锁管理的运作原理。


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


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


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


互斥锁运作示意图


◆ ◆ ◆  ◆ 


我们知道互斥锁可以提供任务之间的互斥机制,用来防止两个任务在同一时刻访问相同的共享资源,那么具体该怎么用呢?Huawei LiteOS提供了互斥锁模块的API接口来供开发者调用。


接口表



功能分类

接口名

描述

互斥锁的创建和删除

LOS_MuxCreate

创建互斥锁

LOS_MuxDelete

删除指定的互斥锁

互斥锁的申请和释放

LOS_MuxPend

申请指定的互斥锁

LOS_MuxPost

释放指定的互斥锁

开发流程:


下面是一个互斥锁使用场景的例子,通过这个例子可以详细了解下互斥锁的开发流程。


  1. 创建互斥锁LOS_MuxCreate
  2. 申请互斥锁LOS_MuxPend
    申请模式有三种: 无阻塞模式、永久阻塞模式、定时阻塞模式
    1. 无阻塞模式:任务需要申请互斥锁,若该互斥锁当前没有任务,或者持有该互斥锁的任务和申请该互斥锁的任务为同一个任务,则申请成功
    2. 永久阻塞模式:任务需要申请互斥锁,若该互斥锁当前没有被占用,则申请成功。否则,该任务进入阻塞态,系统切换到就绪任务中优先级最高者继续执行。任务进入阻塞态后,直到有其他任务释放该互斥锁,阻塞任务才会重新得以执行
    3. 定时阻塞模式:任务需要申请互斥锁,若该互斥锁当前没有被占用,则申请成功。否则该任务进入阻塞态,系统切换到就绪任务中优先级最高者继续执行。任务进入阻塞态后,直到有其他任务释放该互斥锁,或者用户指定时间超时后,阻塞任务才会重新得以执行
  3. 释放互斥锁LOS_MuxPost
    1. 如果有任务阻塞于指定互斥锁,则唤醒最早被阻塞的任务,该任务进入就绪态,并进行任务调度
    2. 如果没有任务阻塞于指定互斥锁,则互斥锁释放成功
  4. 删除互斥锁LOS_MuxDelete

Tips: 

  • 开发过程中,如果遇到互斥锁使用问题,请自行查阅
    HuaweiLiteOSKernel 文档


注意项:


  • 两个任务不可能对同一把互斥锁加锁。如果任务对已被其他任务加锁的互斥锁加锁,该任务会被挂起,直到加锁任务对互斥锁解锁,才能执行对这把互斥锁的加锁操作
  • 互斥锁不能在中断服务例程中使用
  • Huawei LiteOS作为实时操作系统需要保证任务调度的实时性,尽量避免任务的长时间阻塞,因此在获得互斥锁之后,应该尽快释放互斥锁
  • 持有互斥锁的过程中,不得再调用LOS_TaskPriSet等接口更改持有互斥锁任务的优先级


·  动  ·  手  ·  时  ·  刻  ·


终于到了实际操作的环节了,甭废话,直接上代码:


#include "los_mux.h"#include "los_task.h"
/*互斥锁句柄ID*/MUX_HANDLE_T g_Testmux01;/*任务PID*/UINT32 g_TestTaskID01;UINT32 g_TestTaskID02;
VOID Example_MutexTask1(){ UINT32 uwRet;
printf("task1 try to get mutex, wait 10 Tick.\n"); /*申请互斥锁*/ uwRet=LOS_MuxPend(g_Testmux01, 10);
if(uwRet == LOS_OK) { printf("task1 get mutex g_Testmux01.\n"); /*释放互斥锁*/ LOS_MuxPost(g_Testmux01); return; } else if(uwRet == LOS_ERRNO_MUX_TIMEOUT ) { printf("task1 timeout and try to get mutex, wait forever.\n"); /*申请互斥锁*/ uwRet = LOS_MuxPend(g_Testmux01, LOS_WAIT_FOREVER); if(uwRet == LOS_OK) { printf("task1 wait forever,get mutex g_Testmux01.\n"); /*释放互斥锁*/ LOS_MuxPost(g_Testmux01); return; } } return;}
VOID Example_MutexTask2(){ UINT32 uwRet;
printf("task2 try to get mutex, wait forever.\n"); /*申请互斥锁*/ uwRet=LOS_MuxPend(g_Testmux01, LOS_WAIT_FOREVER);
printf("task2 get mutex g_Testmux01 and suspend 100 Tick.\n");
/*任务休眠100 Tick*/ LOS_TaskDelay(100);
printf("task2 resumed and post the g_Testmux01\n"); /*释放互斥锁*/ LOS_MuxPost(g_Testmux01); return;
}
UINT32 Example_TaskEntry(){ UINT32 uwRet; TSK_INIT_PARAM_S stTask1; TSK_INIT_PARAM_S stTask2;
/*创建互斥锁*/ LOS_MuxCreate(&g_Testmux01);
/*锁任务调度*/ LOS_TaskLock();
/*创建任务1*/ memset(&stTask1, 0, sizeof(TSK_INIT_PARAM_S)); stTask1.pfnTaskEntry = (TSK_ENTRY_FUNC)Example_MutexTask1; stTask1.pcName = "MutexTsk1"; stTask1.uwStackSize = OS_TSK_DEFAULT_STACK_SIZE; stTask1.usTaskPrio = 5; uwRet = LOS_TaskCreate(&g_TestTaskID01, &stTask1); if(uwRet != LOS_OK) { printf("task1 create failed .\n"); return LOS_NOK; }
/*创建任务2*/ memset(&stTask2, 0, sizeof(TSK_INIT_PARAM_S)); stTask2.pfnTaskEntry = (TSK_ENTRY_FUNC)Example_MutexTask2; stTask2.pcName = "MutexTsk2"; stTask2.uwStackSize = OS_TSK_DEFAULT_STACK_SIZE; stTask2.usTaskPrio = 4; uwRet = LOS_TaskCreate(&g_TestTaskID02, &stTask2); if(uwRet != LOS_OK) { printf("task2 create failed .\n"); return LOS_NOK; }
/*解锁任务调度*/ LOS_TaskUnlock(); /*任务休眠300 Tick*/ LOS_TaskDelay(300);
/*删除互斥锁*/ LOS_MuxDelete(g_Testmux01);
/*删除任务1*/ uwRet = LOS_TaskDelete(g_TestTaskID01); if(uwRet != LOS_OK) { printf("task1 delete failed .\n"); return LOS_NOK; } /*删除任务2*/ uwRet = LOS_TaskDelete(g_TestTaskID02); if(uwRet != LOS_OK) { printf("task2 delete failed .\n"); return LOS_NOK; }
return LOS_OK;}

本例介绍了互斥锁的基本使用方法,包含互斥锁的创建、申请(无阻塞、定时阻塞、永久阻塞)、释放、删除操作。


运行结果为:

task2 try to get mutex, wait forever.task2 get mutex g_Testmux01 and suspend 100 ticks.task1 try to get mutex, wait 10 ticks.task1 timeout and try to get mutex, wait forever.task2 resumed and post the g_Testmux01task1 wait forever,get mutex g_Testmux01.


详情请参考 HuaweiLiteOSKernel sample_mutex.c源码实现。


好了,LiteOS的互斥锁使用就介绍到这里,如果你有兴趣,可以自己下载LiteOS源码,尝试进行互斥锁功能程序的编写,欢迎随时交流。


更多LiteOS精彩内容:




以上是关于LiteOS 互斥锁机制的主要内容,如果未能解决你的问题,请参考以下文章

LiteOS内核教程05 | 互斥锁(共享资源保护)

读写锁 与 互斥锁

LockSupport.java 中的 FIFO 互斥代码片段

互斥锁 & 共享锁

synchronized学习

Java 中线程同步机制synchronized,互斥锁,死锁,释放锁的详解