【FreeRTOS】互斥锁的使用

简介: 【FreeRTOS】互斥锁的使用

创建、删除

互斥量是一种特殊的二进制信号量,使用互斥量时,先创建、然后去获得、释放它。使用句柄来表示一个互斥量。

SemaphoreHandle_t xSemaphoreCreateMutex( void );

返回值: 返回句柄,非NULL表示成功

void vSemaphoreDelete( SemaphoreHandle_t xSemaphore );

SemaphoreHandle_t xSemaphore:,这里直接传入mutex就可以删除

上锁、开锁

上锁

BaseType_t xSemaphoreGive( SemaphoreHandle_t xSemaphore );

SemaphoreHandle_t xSemaphore:信号量句柄,释放哪个信号量

返回值 :pdTRUE表示成功,如果二进制信号量的计数值已经是1,再次调用此函数则返回失败;

如果计数型信号量的计数值已经是最大值,再次调用此函数则返回失败;

开锁

BaseType_t xSemaphoreTake(SemaphoreHandle_t xSemaphore,
                        TickType_t xTicksToWait);

SemaphoreHandle_t xSemaphore:信号量句柄,释放哪个信号量

TickType_t xTicksToWait:如果无法马上获得信号量,阻塞一会:

  1. 0:不阻塞,马上返回
  2. portMAX_DELAY: 一直阻塞直到成功,
  3. 其他值: 阻塞的Tick个数,可以使用pdMS_TO_TICKS()来指定阻塞时间为若干ms;

返回值 :pdTRUE表示成功

可以看到互斥量的api和信号量的api是一样的,因为互斥量的本质是一个特殊信号量,但是需要注意互斥量不能在ISR中使用;

示例

互斥量的使用场景一般是在多个任务中操作同一个变量的时候会出现使用;下面我们先创建一个三个任务同时操作一个变量的示例;

xTaskCreate((TaskFunction_t )AppTask1,      /* 任务入口函数 */
              (const char*    )"AppTask1",      /* 任务名字 */
              (uint16_t       )128,       /* 任务栈大小 */
              (void*          )NULL,      /* 任务入口函数参数 */
              (UBaseType_t    )1,         /* 任务的优先级 */
               NULL);                         /* 任务控制块指针 */ 
              
              
    xTaskCreate((TaskFunction_t )AppTask2,      /* 任务入口函数 */
              (const char*    )"AppTask2",    /* 任务名字 */
              (uint16_t       )128,       /* 任务栈大小 */
              (void*          )NULL,      /* 任务入口函数参数 */
              (UBaseType_t    )1,         /* 任务的优先级 */
               NULL);                         /* 任务控制块指针 */ 
              
    xTaskCreate((TaskFunction_t )AppTask3,      /* 任务入口函数 */
              (const char*    )"AppTask3",    /* 任务名字 */
              (uint16_t       )128,       /* 任务栈大小 */
              (void*          )NULL,      /* 任务入口函数参数 */
              (UBaseType_t    )1,         /* 任务的优先级 */
               NULL);  
uint32_t count = 0;
static void AppTask1(void *par)
{
    while(1)
    {
        printf("task1 print count = %d\r\n", count++);
    }
}
static void AppTask2(void *par)
{
    while(1)
    {
        printf("task2 print count = %d\r\n", count++);
        
        xSemaphoreGive( xMutex );       /* 给出互斥量 */
    }
}
static void AppTask3(void *par)
{
    while(1)
    {
        printf("task3 print count = %d\r\n", count++);
    }
}

可以看到我们每个任务获取数值都跳跃了非常多的数值,因为这三个任务都是同一优先级所以我们的系统调度会不断的在这三个任务中切换,如果任务刚好处在count++的位置这时候就切换到另外一个线程的count++的位置然而执行自加的这个过程系统调度可以执行上百次最后到打印的位置我们的值已经被其他任务操作了很多次了,所以中间的很多值没有打印出来就直接打印200多这个数值,如果我们加上线程锁,那我们的线程获取到锁过后此时其他两个线程将会一直等待获取到锁的任务操作完发送了释放信号才能拿到锁才能继续操作,那我们上述的任务切换就不会再出现了;

uint32_t count = 0;
SemaphoreHandle_t xMutex;
#define MUTEX 1
static void AppTask1(void *par)
{
    while(1)
    {
        #if MUTEX
        xSemaphoreTake(xMutex,          /* 互斥量句柄 */
                       portMAX_DELAY);  /* 等待时间 */
        #endif
        
        printf("task1 print count = %d\r\n", count++);
        
        #if MUTEX
        xSemaphoreGive( xMutex );       /* 给出互斥量 */
        #endif
    }
}
static void AppTask2(void *par)
{
    while(1)
    {
        #if MUTEX
        xSemaphoreTake(xMutex,          /* 互斥量句柄 */
                       portMAX_DELAY);  /* 等待时间 */
        #endif
        
        printf("task2 print count = %d\r\n", count++);
        
        #if MUTEX
        xSemaphoreGive( xMutex );       /* 给出互斥量 */
        #endif
    }
}
static void AppTask3(void *par)
{
    while(1)
    {
        #if MUTEX
        xSemaphoreTake(xMutex,          /* 互斥量句柄 */
                       portMAX_DELAY);  /* 等待时间 */
        #endif
        
        printf("task3 print count = %d\r\n", count++);
        
        #if MUTEX
        xSemaphoreGive( xMutex );       /* 给出互斥量 */
        #endif
    }
}
#if MUTEX
  xMutex = xSemaphoreCreateMutex();
  #endif
    
    xTaskCreate((TaskFunction_t )AppTask1,      /* 任务入口函数 */
              (const char*    )"AppTask1",      /* 任务名字 */
              (uint16_t       )128,       /* 任务栈大小 */
              (void*          )NULL,      /* 任务入口函数参数 */
              (UBaseType_t    )1,         /* 任务的优先级 */
               NULL);                         /* 任务控制块指针 */ 
              
              
    xTaskCreate((TaskFunction_t )AppTask2,      /* 任务入口函数 */
              (const char*    )"AppTask2",    /* 任务名字 */
              (uint16_t       )128,       /* 任务栈大小 */
              (void*          )NULL,      /* 任务入口函数参数 */
              (UBaseType_t    )1,         /* 任务的优先级 */
               NULL);                         /* 任务控制块指针 */ 
              
    xTaskCreate((TaskFunction_t )AppTask3,      /* 任务入口函数 */
              (const char*    )"AppTask3",    /* 任务名字 */
              (uint16_t       )128,       /* 任务栈大小 */
              (void*          )NULL,      /* 任务入口函数参数 */
              (UBaseType_t    )1,         /* 任务的优先级 */
               NULL); 

结尾

我是凉开水白菜,我们下文见~


相关文章
|
芯片 SoC
两节锂电池充电芯片和充放电电路如何设计
两节锂电池的充放电电路设计主要包括三个部分:A保护电路、B充电电路和C放电电路。A电路(如PW7052芯片)用于检测电压电流并保护电池免受损坏;B电路(如PW4284芯片)负责充电管理,具备过压保护;C电路(如PW2162/PW2163芯片)则负责放电,提供稳定的输出电压。实际设计中,需注意各组件布局与连线,确保电路稳定可靠。
两节锂电池充电芯片和充放电电路如何设计
|
机器学习/深度学习 人工智能 算法
人工智能伦理:机器自主性的双刃剑
【7月更文挑战第18天】随着人工智能技术的飞速发展,机器的自主性日益增强。本文探讨了AI自主性带来的伦理挑战,包括责任归属问题、决策透明度与可解释性的需求,以及可能的社会影响。我们分析了在设计、部署和监管AI系统时必须考虑的关键伦理原则,并提出了一系列策略来确保技术进步不会损害人类价值。
431 4
|
API Python
使用Python requests库下载文件并设置超时重试机制
使用Python的 `requests`库下载文件时,设置超时参数和实现超时重试机制是确保下载稳定性的有效方法。通过这种方式,可以在面对网络波动或服务器响应延迟的情况下,提高下载任务的成功率。
631 1
|
算法 调度
FreeRTOS入门教程(互斥锁的概念和函数使用)
FreeRTOS入门教程(互斥锁的概念和函数使用)
805 0
|
Ubuntu 关系型数据库 数据库
|
存储 传感器 缓存
让QSPI FLASH(W25Q64)支持Fatfs文件系统
让QSPI FLASH(W25Q64)支持Fatfs文件系统
781 0
|
机器学习/深度学习 人工智能 关系型数据库
南京大学提出量化特征蒸馏方法QFD | 完美结合量化与蒸馏,让AI落地更进一步!!!
南京大学提出量化特征蒸馏方法QFD | 完美结合量化与蒸馏,让AI落地更进一步!!!
426 0
|
开发工具 芯片 C++
【GD32F303CCT6BlueBill开箱点灯教程】
本教程教大家如何搭建GD32F303CCT6BlueBill开发环境,涉及点灯程序编译下载和验证。
649 0
|
存储 安全 Java
彻底理解 volatile 关键字及应用场景,面试必问,小白都能看懂!
彻底理解 volatile 关键字及应用场景,面试必问,小白都能看懂!
855 0
彻底理解 volatile 关键字及应用场景,面试必问,小白都能看懂!
【Freertos基础入门】深入浅出freertos互斥量
【Freertos基础入门】深入浅出freertos互斥量
513 0