【ESP32 C++教程】Unit6-4:资源互斥访问

本节主要讲解FreeRTOS任务间如何使用互斥对象来实现资源互斥访问。

互斥访问

在FreeRTOS中,互斥访问通常通过使用互斥量(mutexes)来实现,这是防止多个任务或线程同时访问共享资源的一种机制。互斥量确保在任何时刻,只有一个任务可以访问特定的资源或代码段。这在多任务操作中非常重要,因为它避免了数据竞争和条件竞争,从而保证了程序的正确性和稳定性。

想像一个带锁的箱子,同一时间只能有1个人用钥匙开锁拿里面的东西。

示例:资源互斥访问应用

本示例通过互斥对象来防止多个任务同时访问LED

从 https://gitee.com/billyzh/esp32-cpp-lesson 下载本教程的源码到本地硬盘文件夹,如d:\esp32-cpp-lesson
在VSCode中,选择【文件】->【打开文件夹...】选择上一步保存的文件夹打开

打开项目后,选择config.h文件,修改第10行为
#define APP_LESSON64_A 1

打开unit6-lesson64a/board_config.h文件,设置LED使用的引脚,
#define BUILTIN_LED_PIN GPIO_NUM_4
配置启用GpioLed
#define CONFIG_USE_LED_GPIO 1

创建LED实例,代码如下(unit6-lesson64a/my_board.cpp):

MyBoard::MyBoard() : Board() {
    Log::Info(TAG, "===== Create Board ...... =====");

    Log::Info(TAG, "initial led.");
    led_ = new GpioLed(BUILTIN_LED_PIN, false);

    Log::Info( TAG, "===== Board config completed. =====");
}

程序很简单,就是创建一个GpioLed实例。

互斥对象应用

代码如下(unit6-lesson64a/my_application.cpp):

void MyApplication::OnInit() {
    mutex_ = new FrtMutex(); // 创建FreeRTOS互斥对象

    task1_ = new Task("Task1");
    task1_->OnLoop([this](){
        Task1Loop();
    });
    task1_->Start( 4096, tskIDLE_PRIORITY+1);
    
    task2_ = new Task("Task2");
    task2_->OnLoop([this](){
        Task2Loop();
    });
    task2_->Start( 4096, tskIDLE_PRIORITY+1);
}

void MyApplication::Task1Loop() {
    AccessResource("task1");
    delay(200);
}

void MyApplication::Task2Loop() {
    AccessResource("task2");
    delay(300);
}

void MyApplication::AccessResource(const std::string& owner) {
    MutexGuard guard(mutex_, 0);
    if (guard.IsLocked())
    {
        // 独占访问代码
        Led *led = Board::GetInstance().GetLed();
        led->TurnOn();
        delay(500);
        led->TurnOff();
        delay(500);

        count_++;
        Log::Info(TAG, "call by %s, count: %d", owner.c_str(), count_);
    }
}

程序解读
1. 在OnInit方法内,创建一个互斥对象Mutex实例和两个Task实例,然后启动任务;
2. Task1Loop方法是任务1的循环体方法,具体为每200ms调用AccessResource方法;
3. Task2Loop方法是任务2的循环体方法,具体为每200ms调用AccessResource方法;
4. AccessResource方法内通过MutexGuard的构造函数来尝试加锁mutex_,若加锁成功,则闪烁LED,方法执行完毕后guard实例释放,在MutexGuard的析构函数释放mutex_

Mutex类和MutexGuard类

在本框架中Mutex类目前有两个实现FrtMutex(FreeRTOS互斥量)和StdMutex(标准C++库互斥量), 本课只介绍FrtMutex类。

FrtMutex代码如下(framework/sys/mutex/frt_mutex.h):

class FrtMutex :  public Mutex {
public:
    FrtMutex() 
    {
        mutex_semaphore_ = xSemaphoreCreateMutex(); // 创建互斥信号量
    }

    ~FrtMutex()
    {
        vSemaphoreDelete(mutex_semaphore_);
    }

    bool Lock(int timeout_ms = 0) override 
    {
        TickType_t tick = timeout_ms>=0 ? pdMS_TO_TICKS(timeout_ms) : portMAX_DELAY;
        return xSemaphoreTake(mutex_semaphore_, tick) == pdTRUE;
    }

    void Unlock() override 
    {
        xSemaphoreGive(mutex_semaphore_);
    }

private:
    SemaphoreHandle_t mutex_semaphore_ = NULL;
};

程序解读
FrtMutex是一个非常典型的用对象封装C代码的例子,在构造函数/析构函数中创建和删除互斥量, 在Lock/Unlock方法中进行加锁和释放锁。

MutexGuard代码如下(framework/sys/mutex.h):

class MutexGuard {
public:
    MutexGuard(Mutex *mutex, int timeout_ms=0) : mutex_(mutex) {
        is_locked_ = mutex_->Lock(timeout_ms);
        if (!is_locked_) 
        {
            Log::Error("Mutex", "Failed to lock mutex");
        }
    }

    ~MutexGuard() {
        if (is_locked_) 
        {
            mutex_->Unlock();
        }
    }

    MutexGuard(const MutexGuard&) = delete;
    MutexGuard& operator=(const MutexGuard&) = delete;

    const bool IsLocked() const { return is_locked_; }
private:
    Mutex *mutex_;
    bool is_locked_;
};

程序解读
MutexGuard是一个辅助类,它实现在构造函数和析构函数中实施一对相反的操作,此处为互斥对象的加锁和释放锁。
这样可以让我们在方法开头处实例此类(调用构造函数),方法结束后变量超出作用域释放(调用析构函数)来完成这一对操作的自动处理。

编译项目并上传开发板检验

- 本文由用户 老张 发布,文中观点仅代表作者本人,不代表本站立场。
- 如需转载,请联系作者;如有侵权,请联系本站处理。

18:14   阅读(1)   评论(0)
 标签: 创客 ESP32 ESP32-ArduinoFx

涨知识
勾股定理

勾股定理,是一个基本的几何定理,指直角三角形的两条直角边的平方和等于斜边的平方。中国古代称直角三角形为勾股形,并且直角边中较小者为勾,另一长直角边为股,斜边为弦,所以称这个定理为勾股定理,也有人称商高定理。

评论:
相关文章
ESP32 Guru Meditation Error报错定位分析

在ESP32的开发,经常会有系统崩溃一直重启的情况,那么如何快速定位出现异常的代码呢?


【ESP32 C++教程】Unit6-3 FreeRTOS任务间通信

本节主要讲解FreeRTOS任务间如何使用消息队列、事件组和二进制信号量进行通信。


【ESP32 C++教程】Unit6-2 FreeRTOS多任务

本节主要讲解Task类,FreeRTOS多任务的使用。


【ESP32 C++教程】Unit6-1 定时器

本节主要讲解Timer类,FreeRTOS定时器的使用。


【ESP32 C++教程】Unit5-2 执行器件之舵机

本节主要讲解舵机驱动类和用按键控制舵机。


【ESP32 C++教程】Unit5-1 执行器件之继电器

本节主要讲解执行器件类型和用按键控制继电器。


【ESP32 C++教程】Unit4-3 红外接收和遥控

本小节主要讲解红外接收和遥控器件,以及遥控操作LED。


【ESP32 C++教程】Unit4-2 模拟量传感器

本小节讲解模拟量传感器使用,旋转电位器,DHT11温湿度传感器和实现自定义传感器类。


【ESP32 C++教程】Unit4-1 数字量传感器

本小节讲解Sensor类及派生类、数字量传感器使用和传感器的推荐交互流程。


【ESP32 C++教程】Unit3-2 触摸输入

本小节讲解ESP32内置触摸引脚的用法,