【FreeRTOS】互斥锁的使用

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

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



创建、删除

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

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++的位置这时候就切换到另外一个线程的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);	

在这里插入图片描述

结尾

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

凉开水白菜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值