• 【FreeRTOS】互斥锁的使用


    ❤️作者主页:凉开水白菜
    ❤️作者简介:共同学习,互相监督,热于分享,多加讨论,一起进步!
    ❤️专栏资料:https://pan.baidu.com/s/1nc1rfyLiMyw6ZhxiZ1Cumg?pwd=free
    ❤️点赞 👍 收藏 ⭐再看,养成习惯

    订阅的粉丝可通过PC端左侧加我微信,可对文章的内容进行一对一答疑!



    创建、删除

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

    SemaphoreHandle_t xSemaphoreCreateMutex( void );
    
    • 1

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

    void vSemaphoreDelete( SemaphoreHandle_t xSemaphore );
    
    • 1

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

    上锁、开锁

    上锁

    BaseType_t xSemaphoreGive( SemaphoreHandle_t xSemaphore );
    
    • 1

    SemaphoreHandle_t xSemaphore:信号量句柄,释放哪个信号量
    返回值 :pdTRUE表示成功,如果二进制信号量的计数值已经是1,再次调用此函数则返回失败;
    如果计数型信号量的计数值已经是最大值,再次调用此函数则返回失败;

    开锁

    BaseType_t xSemaphoreTake(SemaphoreHandle_t xSemaphore,
                       			TickType_t xTicksToWait);
    
    • 1
    • 2

    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);	 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    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++);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    然后我们可以看到我们的串口助手中打印的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
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
      #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);	
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    在这里插入图片描述

    结尾

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

  • 相关阅读:
    flink的几种常见的执行模式
    【flask进阶】Flask实现自定义分页(python web通用)
    DAY6-力扣刷题
    SpringBoot基础入门
    基于BP神经网络对鸢尾花数据集分类
    Guava-字符串工具
    jar -jar运行原理
    机器学习 不均衡数据采样方法:imblearn 库的使用
    #案例:演示 web 自动化测试环境是否 OK(针对:Chrome 浏览器)
    性能测试之性能测试指标详解
  • 原文地址:https://blog.csdn.net/qq_43581670/article/details/127688331