> 文档中心 > 鸿蒙Hi3861学习九-Huawei LiteOS-M(互斥锁)

鸿蒙Hi3861学习九-Huawei LiteOS-M(互斥锁)


一、简介

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

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

        当有任务占用公共资源时,互斥锁处于闭锁状态,这个任务获得该互斥锁的使用权。

        当该任务释放公共资源时,互斥锁被开锁,任务失去该互斥锁的所有权。

        当一个任务持有互斥锁时其他任务将不能再对该互斥锁进行开锁或持有

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

        更多关于互斥锁的概念以及优先级翻转问题的概念,可以参考如下链接:FreeRTOS学习五(信号量)_freertos信号量用法_t_guest的博客-CSDN博客

Mutex Management

二、 运行机制

        多任务环境下会存在多个任务访问同一公共资源的场景,而有些公共资源时非共享的,需要任务进行独占式处理。此时,就需要互斥锁出面了。

        用互斥锁处理非共享资源的同步访问时,如果有任务访问该资源,则互斥锁切换为闭锁状态。此时,其他任务如果想访问这个公共资源,则会被阻塞直到互斥锁被持有该锁的任务释放后,其他任务才能重新访问该公共资源,并且互斥锁会再次转换为闭锁状态。如此确保在同一时刻,只有一个任务正在访问这个公共资源,保证了公共资源操作的完整性

        优先级翻转,之前的文章中已经介绍过了,这里就不再过多介绍。有兴趣可以看上述的链接。

 三、API介绍

      osMutexNew

        函数功能:

        创建互斥锁。不可在中断中使用

        函数原型:

osMutexId_t osMutexNew(const osMutexAttr_t *attr)

        参数:

        attr:属性,自定义内存时使用。默认NULL

        返回值:

        锁标识符

        实例:

osMutexId_t mutex_id;mutex_id = osMutexNew(NULL);

      osMutexAcquire

        函数功能:

        获取互斥锁。如果为闭锁状态,则阻塞任务等待直到超时为止。如果为开锁状态,则切换为闭锁状态。不可在中断中使用

        函数原型:

osStatus_t osMutexAcquire(osMutexId_t mutex_id, uint32_t timeout)

        参数:

        mutex_id:锁标识符。创建锁osMutexNew时获取

        timeout:等待超时时间。osWaitForever死等

        返回值:

        osOK:成功

        其他值:失败

        实例:

osMutexId_t mutex_id;osMutexAcquire(mutex_id, osWaitForever);

      osMutexRelease

        函数功能:

        释放锁。如果锁为闭锁状态,释放后才能被其他任务获取到。不可在中断中使用

        函数原型:

osStatus_t osMutexRelease(osMutexId_t mutex_id)

        参数:

        mutex_id:锁标识符。创建锁osMutexNew时获取。

        返回值:

        osOK:成功

        其他值:失败

        实例:

osMutexId_t mutex_id;osMutexRelease(mutex_id);

      osMutexDelete

        函数功能:

        删除锁。不可在中断中使用。

        函数原型:

osStatus_t osMutexDelete(osMutexId_t mutex_id)

        参数:

        mutex_id:锁标识符。创建锁osMutexNew时获取。

        返回值:

        osOK:成功

        其他值:失败

        实例:

osMutexId_t mutex_id;osMutexDelete(mutex_id);

四、实例

        创建三个任务,三个任务的优先级递增。同时操作互斥锁,看看结果如何。

#define LOG_I(fmt, args...)   printf(" - [TIMER]:"fmt"\r\n",osKernelGetTickCount(),##args);#define LOG_E(fmt, args...)   printf("-[TIMER_ERR]>>>>>>>>>>>>:"fmt"\r\n",osKernelGetTickCount(), ##args);osMutexId_t mutex_id;void HighPrioThread(void){  osDelay(50U);  while (1)  {    LOG_I("HighPrioThread get before");    osMutexAcquire(mutex_id, osWaitForever);    LOG_I("HighPrioThread get after");    osDelay(50U);    LOG_I("HighPrioThread mutex release before");    osMutexRelease(mutex_id);    LOG_I("HighPrioThread mutex release after");  }}void MidPrioThread(void){  osDelay(10U);  while (1)  {    LOG_I("MidPrioThread get before");    osMutexAcquire(mutex_id, osWaitForever);    LOG_I("MidPrioThread get after");    osDelay(100);    LOG_I("MidPrioThread mutex release before");    osMutexRelease(mutex_id);    LOG_I("MidPrioThread mutex release after");  }}void LowPrioThread(void){  while (1)  {    LOG_I("LowPrioThread get before");    osMutexAcquire(mutex_id, osWaitForever);    LOG_I("LowPrioThread get after");    osDelay(200U);    LOG_I("LowPrioThread mutex release before");    osMutexRelease(mutex_id);    LOG_I("LowPrioThread mutex release after");  }}void Hello_World(void){    LOG_I("Test mutex");    mutex_id = osMutexNew(NULL);    if (mutex_id == NULL)    { LOG_E("Falied to create Mutex!\n");    }    osThreadAttr_t attr;    attr.attr_bits = 0U;    attr.cb_mem = NULL;    attr.cb_size = 0U;    attr.stack_mem = NULL;    attr.stack_size = 1024 * 4;    attr.name = "HighPrioThread";    attr.priority = osPriorityNormal2;    if (osThreadNew((osThreadFunc_t)HighPrioThread, NULL, &attr) == NULL)    { LOG_E("Falied to create HighPrioThread!\n");    }    attr.name = "MidPrioThread";    attr.priority = osPriorityNormal1;    if (osThreadNew((osThreadFunc_t)MidPrioThread, NULL, &attr) == NULL)    { LOG_E("Falied to create MidPrioThread!\n");    }    attr.name = "LowPrioThread";    attr.priority = osPriorityNormal;    if (osThreadNew((osThreadFunc_t)LowPrioThread, NULL, &attr) == NULL)    { LOG_E("Falied to create LowPrioThread!\n");    }}

        看结果:

         任务1优先级任务2优先级任务3优先级

        启动后,任务1延迟500ms执行任务2延迟100ms执行任务3不延迟

        注:以下编号与图片上编号对应

        1.任务3率先执行,先获取到互斥锁,使锁为闭锁状态。模拟操作共享数据。

        2.任务2延迟完成,开始执行,获取互斥锁,发现为闭锁状态,则挂起任务等待。

        3.任务1延迟完成,开始执行,获取互斥锁,发现为闭锁状态,则挂起任务等待。

        4.任务3数据操作完成,释放互斥锁。

        5.任务1因为优先级最高即使任务2先等待,但是还是任务1抢占到控制权然后获取互斥锁。然后开始操作数据。

        6.任务3继续执行。

        7.任务3获取互斥锁,发现为闭锁状态,则挂起任务等待。

        8.9。任务1继续执行

        10.任务1获取互斥锁。虽然任务1刚才释放了互斥锁,但是任务2一直在等待互斥锁,在任务1释放的瞬间就获取到互斥锁了。所以这里即使任务1优先级高,也无法获取到互斥锁。

        11.任务2模拟操作数据

        12.任务2操作数据完成,释放互斥锁。

        13.任务1因为优先级高,这里获取到互斥锁,模拟操作数据。

        这里可能会有疑问,为什么在10阶段,任务2明明优先级低,却能获取到互斥锁。而13这里任务3缺获取不到。这是因为在10阶段,任务2是在任务1释放互斥锁时,等待任务队列中优先级最高的任务。而13阶段,任务2在释放信号量时,任务1早已经在等待了。任务1是等待队列中优先级最高的。所以互斥锁才会被任务1截胡。

        从运行结果可以看出来,在同时等待互斥锁时,高优先级的任务总会有限获取到信号量,跟等待顺序是无关的。