【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); 

结尾

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


相关文章
|
人工智能 计算机视觉
开源视频字幕模型Video ReCap可最长处理2小时
【2月更文挑战第9天】开源视频字幕模型Video ReCap可最长处理2小时
451 3
开源视频字幕模型Video ReCap可最长处理2小时
|
网络协议 前端开发 数据安全/隐私保护
利用C语言实现URL解析的基本方法之优秀
今天主要来学习一下,如何利用URL,实现对应的解析过程。
850 0
利用C语言实现URL解析的基本方法之优秀
|
2月前
|
Ubuntu 关系型数据库 MySQL
MySQL包安装 -- Debian系列(离线DEB包安装MySQL)
本文详细介绍了在Ubuntu 24.04、22.04、20.04及Debian 12系统上,通过离线DEB包安装MySQL 8.0和8.4版本的完整步骤。涵盖下载地址、依赖处理、dpkg安装顺序、配置方法及服务启动验证,确保用户可顺利部署MySQL数据库。
766 0
MySQL包安装 -- Debian系列(离线DEB包安装MySQL)
|
开发工具 git 缓存
Git忽略规则.gitignore不生效
在项目开发过程中个,一般都会添加 .gitignore 文件,规则很简单,但有时会发现,规则不生效。 原因是 .gitignore 只能忽略那些原来没有被track的文件,如果某些文件已经被纳入了版本管理中,则修改.gitignore是无效的。
62030 4
|
算法 调度
FreeRTOS入门教程(互斥锁的概念和函数使用)
FreeRTOS入门教程(互斥锁的概念和函数使用)
932 0
|
芯片 SoC
两节锂电池充电芯片和充放电电路如何设计
两节锂电池的充放电电路设计主要包括三个部分:A保护电路、B充电电路和C放电电路。A电路(如PW7052芯片)用于检测电压电流并保护电池免受损坏;B电路(如PW4284芯片)负责充电管理,具备过压保护;C电路(如PW2162/PW2163芯片)则负责放电,提供稳定的输出电压。实际设计中,需注意各组件布局与连线,确保电路稳定可靠。
两节锂电池充电芯片和充放电电路如何设计
|
机器学习/深度学习 人工智能 算法
人工智能伦理:机器自主性的双刃剑
【7月更文挑战第18天】随着人工智能技术的飞速发展,机器的自主性日益增强。本文探讨了AI自主性带来的伦理挑战,包括责任归属问题、决策透明度与可解释性的需求,以及可能的社会影响。我们分析了在设计、部署和监管AI系统时必须考虑的关键伦理原则,并提出了一系列策略来确保技术进步不会损害人类价值。
499 4
|
消息中间件 算法 调度
FreeRTOS 任务调度和任务的状态
FreeRTOS 任务调度和任务的状态
FreeRTOS 任务调度和任务的状态
|
C语言
C语言中如何实现数据帧封装与解析
在计算机网络通信中,数据帧的封装与解析是非常重要的环节。本文将介绍一种基于C语言的实现方法,旨在帮助读者理解数据帧的结构和实现过程。
482 1
|
存储 分布式计算 大数据
大数据处理平台的架构演进:从批处理到实时流处理
大数据处理平台的架构演进:从批处理到实时流处理
587 0