FreeRTOS【10】互斥锁使用

1.开发背景

       FreeRTOS 提供了多线程控制,并且是支持高低优先级抢占,这就意味着低优先级线程在执行任务时有可能被高优先级线程打断,如果两个线程共同操作同一个资源可能会导致不可意料的结果,因此,访问共享内存时需要添加互斥操作,因此互斥锁就有了。

        有人可能会考虑用信号量去实现互斥的功能,实时上也是可以的,FreeRTOS的互斥锁是二值信号量的一个特例,相对于二值信号量,互斥锁会有优先级继承的特性:

        【如果另一个更高优先级的任务尝试获取相同的互斥锁, 则将暂时提高“获取”互斥锁的任务的优先级。 拥有互斥锁的任务 “继承”试图“获取”相同 互斥锁的任务的优先级。 这意味着必须始终“归还”互斥锁,否则 优先级较高的任务将始终无法获得互斥锁,而优先级较低 的始终无法“取消继承”优先级。】

2.开发需求

设计实验1:利用互斥锁实现资源保护

        1)创建低优先级和高优先级线程

        2)低优先级线程先 100ms 获取互斥锁,在互斥锁期间 1000ms 后释放互斥锁

        3)高优先级线程后 100ms 尝试获取互斥锁

设计实验2:验证优先级继承现象

        1)创建低优先级和高优先级线程

        2)低优先级线程取锁后获取当前线程优先级

        3)低优先级线程等待高优先级线程取锁后,获取当前线程优先级

        4)等待高优先级线程获取互斥锁后,再获取当前线程优先级

3.开发环境

        window10 + MDK + STM32F429 + FreeRTOS10.3.1

4.实现步骤

4.1 互斥锁资源保护

4.1.1 软件编码
#include "appTest.h"

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include "mspDwt.h"
#include "mspGpio.h"
#include "mspExti.h"

#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"

#include "appLog.h"

typedef struct
{
    /* 信号量 */
    SemaphoreHandle_t lock;     // 信号锁
    
    /* 创建任务 */
    TaskHandle_t taskLow;       // 低优先级线程
    TaskHandle_t taskHigh;      // 高优先级线程
    
}Ctrl_t;

/* 文件指针 */
static Ctrl_t s_ctrl = {0};
static Ctrl_t *p = &s_ctrl;
static void TaskLow(void *pvParameters);
static void TaskHigh(void *pvParameters);

/* 接收线程 */
static void TaskLow(void *pvParameters)
{
    vTaskDelay(100);
    
    for ( ; ; )
    {
        /* 取锁 */
        xSemaphoreTake(p->lock, portMAX_DELAY);
        Log_Debug("%s 取锁成功\r\n", __func__);
        
        /* 等待高优先级线程取锁 */
        vTaskDelay(1000);
        
        Log_Debug("%s 解锁成功\r\n", __func__);
        xSemaphoreGive(p->lock);
    }
}

/* 发送线程 */
static void TaskHigh(void *pvParameters)
{
    vTaskDelay(200);
    
    for ( ; ; )
    {
        xSemaphoreTake(p->lock, portMAX_DELAY);
        Log_Debug("%s 取锁成功\r\n", __func__);
        
        vTaskDelay(1000);
        
        Log_Debug("%s 解锁成功\r\n", __func__);
        xSemaphoreGive(p->lock);
        
        vTaskDelay(100);
    }
}

/* 测试初始化 */
void aTest_Init(void)
{
    /* 创建信号锁 */
    p->lock = xSemaphoreCreateMutex();
    
    /* 创建动态任务 */
    xTaskCreate(TaskLow,  "TaskLow",   500, NULL, 4, &p->taskLow);
    xTaskCreate(TaskHigh, "TaskHigh",  500, NULL, 5, &p->taskHigh);
}

/* Key2 PC13   Key0 PH3 Key1 PH2 */
void Exti13_TriggerInterrupt(void)
{
    mspExti_Close(13);
    
    if (mspGpio_GetInput("PC13") == 0)
    {
        
    }
}


4.1.2 结果显示

4.2 互斥锁优先级继承

4.2.1 软件编码
#include "appTest.h"

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include "mspDwt.h"
#include "mspGpio.h"
#include "mspExti.h"

#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"

#include "appLog.h"

typedef struct
{
    /* 信号量 */
    SemaphoreHandle_t lock;     // 信号锁
    
    /* 创建任务 */
    TaskHandle_t taskLow;       // 低优先级线程
    TaskHandle_t taskHigh;      // 高优先级线程
    
}Ctrl_t;

/* 文件指针 */
static Ctrl_t s_ctrl = {0};
static Ctrl_t *p = &s_ctrl;
static void TaskLow(void *pvParameters);
static void TaskHigh(void *pvParameters);

/* 接收线程 */
static void TaskLow(void *pvParameters)
{
    vTaskDelay(100);
    UBaseType_t priority = 0;
    
    for ( ; ; )
    {
        /* 取锁前查看一下线程优先级 */
        priority = uxTaskPriorityGet(NULL);
        Log_Debug("%s 低优先级线程取锁前查看优先级 priority = %d\r\n", __func__, priority);
        
        /* 取锁 */
        xSemaphoreTake(p->lock, portMAX_DELAY);
        Log_Debug("%s 取锁成功\r\n", __func__);
        
        /* 取锁前查看一下线程优先级 */
        priority = uxTaskPriorityGet(NULL);
        Log_Debug("%s 低优先级线程取锁后查看优先级 priority = %d\r\n", __func__, priority);
        
        /* 等待高优先级线程取锁 */
        vTaskDelay(1000);
        
        /* 查看线程优先级 */
        priority = uxTaskPriorityGet(NULL);
        Log_Debug("%s 低优先级线程等高优先级线程取锁后查看优先级 priority = %d\r\n", __func__, priority);
        
        xSemaphoreGive(p->lock);
    }
}

/* 发送线程 */
static void TaskHigh(void *pvParameters)
{
    vTaskDelay(200);
    
    for ( ; ; )
    {
        xSemaphoreTake(p->lock, portMAX_DELAY);
        Log_Debug("%s 取锁成功\r\n", __func__);
        
        vTaskDelay(1000);
        
//        xSemaphoreGive(p->lock);
    }
}

/* 测试初始化 */
void aTest_Init(void)
{
    /* 创建信号锁 */
    p->lock = xSemaphoreCreateMutex();
    
    /* 创建动态任务 */
    xTaskCreate(TaskLow,  "TaskLow",   500, NULL, 4, &p->taskLow);
    xTaskCreate(TaskHigh, "TaskHigh",  500, NULL, 5, &p->taskHigh);
}

/* Key2 PC13   Key0 PH3 Key1 PH2 */
void Exti13_TriggerInterrupt(void)
{
    mspExti_Close(13);
    
    if (mspGpio_GetInput("PC13") == 0)
    {
    }
}


4.2.2 结果显示

### FreeRTOS互斥锁使用方法 在FreeRTOS中,互斥锁是一种重要的同步机制,主要用于保护共享资源,防止多个任务同时访问而导致的数据不一致问题。以下是关于如何正确使用FreeRTOS中的互斥锁的相关说明: #### 创建互斥锁 创建互斥锁可以通过调用`xSemaphoreCreateMutex()`函数实现。该函数会返回一个句柄(handle),用于后续操作此互斥锁。如果成功创建,则返回非NULL值;否则返回NULL。 ```c SemaphoreHandle_t xMutex = xSemaphoreCreateMutex(); if (xMutex == NULL) { // 错误处理逻辑 } ``` 上述代码展示了如何创建一个互斥锁实例[^1]。 #### 获取互斥锁 当某个任务需要访问受保护的共享资源时,应先尝试获取互斥锁。这通常通过`xSemaphoreTake()`函数完成。该函数接受两个参数:第一个是互斥锁的句柄,第二个是指定的最大等待时间(以ticks为单位)。如果立即可用,则直接获得锁并继续执行;如果不可用,则阻塞当前任务直到超时或锁被释放。 ```c if (xSemaphoreTake(xMutex, portMAX_DELAY)) { // 成功获取到锁,可以安全地访问共享资源 } else { // 超时未获取到锁的情况下的错误处理 } ``` 这里需要注意的是,在实际应用中应当合理设置等待时间而非总是采用无限期等待(`portMAX_DELAY`)的方式,以免影响系统整体性能和响应速度[^4]。 #### 释放互斥锁 一旦完成了对共享资源的操作之后,应及时释放所持有的互斥锁以便其他可能正在排队等候的任务能够尽快取得使用权。这是通过调用`xSemaphoreGive()`来达成的。 ```c // 完成对sharedVariable的操作后... xSemaphoreGive(xMutex); ``` 以上即构成了基本的互斥锁使用流程——创建、获取、使用及最后释放的过程[^2]。 #### 需要注意的问题 尽管互斥锁能有效解决多线程环境下的资源共享难题,但在具体实践中还需留意诸如优先级反转现象及其解决方案(如支持的优先级继承协议),以及可能出现的各种形式的死锁状况等问题[^3]。 ### 示例代码 下面给出一段完整的示例程序片段展示如何利用FreeRTOS里的互斥锁来进行简单的临界区控制: ```c #include "semphr.h" void vTaskFunction(void *pvParameters){ static int sharedVariable = 0; while(1){ if (xSemaphoreTake(xMutex, pdMS_TO_TICKS(100))) { /* Critical Section Start */ sharedVariable++; /* Critical Section End */ xSemaphoreGive(xMutex); } // 其他非关键部分的工作... } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值