LiteOS 互斥锁机制
Posted 易飞澈信息科技
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LiteOS 互斥锁机制相关的知识,希望对你有一定的参考价值。
基本概念
互斥锁又称互斥型信号量,是一种特殊的二值性信号量,用于实现对共享资源的独占式处理。
任意时刻互斥锁的状态只有两种,开锁或闭锁。当有任务持有时,互斥锁处于闭锁状态,这个任务获得该互斥锁的所有权。当该任务释放它时,该互斥锁被开锁,任务失去该互斥锁的所有权。当一个任务持有互斥锁时,其他任务将不能再对该互斥锁进行开锁或持有。
多任务环境下往往存在多个任务竞争同一共享资源的应用场景,互斥锁可被用于对共享资源的保护,从而实现独占式访问。另外,互斥锁可以解决信号量存在的优先级翻转问题。
互斥锁特点:
通过优先级继承算法,解决优先级翻转问题
◆ ◆ ◆ ◆ ◆
接下来看下互斥锁管理的运作原理。
多任务环境下会存在多个任务访问同一公共资源的场景,而有些公共资源是非共享的,需要任务进行独占式处理。
互斥锁是怎样来避免这种冲突的呢?
当一个任务访问某个非共享公共资源时,互斥锁为加锁状态。此时其他任务如果想访问这个公共资源则会被阻塞,直到互斥锁被该任务释放后,才能重新访问公共资源,此时互斥锁再次上锁,如此确保同一时刻只有一个任务正在访问这个公共资源,保证了共享数据操作的完整性。
互斥锁运作示意图
◆ ◆ ◆ ◆ ◆
我们知道互斥锁可以提供任务之间的互斥机制,用来防止两个任务在同一时刻访问相同的共享资源,那么具体该怎么用呢?Huawei LiteOS提供了互斥锁模块的API接口来供开发者调用。
接口表
功能分类 |
接口名 |
描述 |
---|---|---|
互斥锁的创建和删除 |
LOS_MuxCreate |
创建互斥锁 |
LOS_MuxDelete |
删除指定的互斥锁 |
|
互斥锁的申请和释放 |
LOS_MuxPend |
申请指定的互斥锁 |
LOS_MuxPost |
释放指定的互斥锁 |
开发流程:
下面是一个互斥锁使用场景的例子,通过这个例子可以详细了解下互斥锁的开发流程。
-
创建互斥锁LOS_MuxCreate -
申请互斥锁LOS_MuxPend 申请模式有三种: 无阻塞模式、永久阻塞模式、定时阻塞模式 -
无阻塞模式:任务需要申请互斥锁,若该互斥锁当前没有任务,或者持有该互斥锁的任务和申请该互斥锁的任务为同一个任务,则申请成功 -
永久阻塞模式:任务需要申请互斥锁,若该互斥锁当前没有被占用,则申请成功。否则,该任务进入阻塞态,系统切换到就绪任务中优先级最高者继续执行。任务进入阻塞态后,直到有其他任务释放该互斥锁,阻塞任务才会重新得以执行 -
定时阻塞模式:任务需要申请互斥锁,若该互斥锁当前没有被占用,则申请成功。否则该任务进入阻塞态,系统切换到就绪任务中优先级最高者继续执行。任务进入阻塞态后,直到有其他任务释放该互斥锁,或者用户指定时间超时后,阻塞任务才会重新得以执行 -
释放互斥锁LOS_MuxPost -
如果有任务阻塞于指定互斥锁,则唤醒最早被阻塞的任务,该任务进入就绪态,并进行任务调度 -
如果没有任务阻塞于指定互斥锁,则互斥锁释放成功 -
删除互斥锁LOS_MuxDelete
Tips:
开发过程中,如果遇到互斥锁使用问题,请自行查阅
HuaweiLiteOSKernel 文档
注意项:
-
两个任务不可能对同一把互斥锁加锁。如果任务对已被其他任务加锁的互斥锁加锁,该任务会被挂起,直到加锁任务对互斥锁解锁,才能执行对这把互斥锁的加锁操作 -
互斥锁不能在中断服务例程中使用 -
Huawei LiteOS作为实时操作系统需要保证任务调度的实时性,尽量避免任务的长时间阻塞,因此在获得互斥锁之后,应该尽快释放互斥锁 -
持有互斥锁的过程中,不得再调用LOS_TaskPriSet等接口更改持有互斥锁任务的优先级
· 动 · 手 · 时 · 刻 ·
终于到了实际操作的环节了,甭废话,直接上代码:
/*互斥锁句柄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_Testmux01
task1 wait forever,get mutex g_Testmux01.
详情请参考 HuaweiLiteOSKernel sample_mutex.c源码实现。
好了,LiteOS的互斥锁使用就介绍到这里,如果你有兴趣,可以自己下载LiteOS源码,尝试进行互斥锁功能程序的编写,欢迎随时交流。
更多LiteOS精彩内容:
以上是关于LiteOS 互斥锁机制的主要内容,如果未能解决你的问题,请参考以下文章