首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >FreeRTOS互斥/二进制信号量与死锁

FreeRTOS互斥/二进制信号量与死锁
EN

Stack Overflow用户
提问于 2022-09-20 18:51:40
回答 1查看 145关注 0票数 0

我是FreeRTOS的新手,所以我从我认为是一个很棒的教程开始,这个教程是由肖恩·海梅尔提供的。我还在实现在ESP32 DevkitC V4中编写的代码。

但是,我认为我不理解二进制信号量和互斥量之间的区别。当我运行这段代码时,试图避免使用两个互斥保护关键部分(如本教程所示)的两个任务之间的死锁。

代码语言:javascript
运行
复制
// Use only core 1 for demo purposes
#if CONFIG_FREERTOS_UNICORE
  static const BaseType_t app_cpu = 0;
#else
  static const BaseType_t app_cpu = 1;
#endif

//Settings
TickType_t mutex_timeout = 1000 / portTICK_PERIOD_MS;
//Timeout for any task that tries to take a mutex!

//Globals
static SemaphoreHandle_t mutex_1;
static SemaphoreHandle_t mutex_2;

//**********************************************************
//Tasks

//Task A (High priority)
void doTaskA(void*parameters){

    while(1){

        //Take mutex 1
        if( xSemaphoreTake(mutex_1, mutex_timeout) == pdTRUE){
            Serial.println("Task A took mutex 1");
            vTaskDelay(1 / portTICK_PERIOD_MS);    
        //Take mutex 2
            if(xSemaphoreTake(mutex_2, mutex_timeout) == pdTRUE){
                Serial.println("Task A took mutex 2");

                //Critical section protected by 2 mutexes
                Serial.println("Task A doing work");
                vTaskDelay(500/portTICK_PERIOD_MS);         //simulate that critical section takes 500ms
            } else {
                Serial.println("Task A timed out waiting for mutex 2. Trying again...");
                }
        } else {
            Serial.println("Task A timed out waiting for mutex 1. Trying again...");
        }

        //Return mutexes
        xSemaphoreGive(mutex_2);
        xSemaphoreGive(mutex_1);

        Serial.println("Task A going to sleep");
        vTaskDelay(500/portTICK_PERIOD_MS);
        //Wait to let other task execute
    }
}

//Task B (low priority)
void doTaskB(void * parameters){

    while(1){

        //Take mutex 2 and wait to force deadlock
        if(xSemaphoreTake(mutex_2, mutex_timeout)==pdTRUE){
            Serial.println("Task B took mutex 2");
            vTaskDelay(1 / portTICK_PERIOD_MS);         

            if(xSemaphoreTake(mutex_1, mutex_timeout) == pdTRUE){
                Serial.println("Task B took mutex 1");
        

                //Critical section protected by 2 mutexes
                Serial.println("Task B doing work");
                vTaskDelay(500/portTICK_PERIOD_MS);         //simulate that critical section takes 500ms
            } else {
                Serial.println("Task B timed out waiting for mutex 1");
                }
        } else {
            Serial.println("Task B timed out waiting for mutex 2");
            }

        //Return mutexes
        xSemaphoreGive(mutex_1);
        xSemaphoreGive(mutex_2);

        Serial.println("Task B going to sleep");
        vTaskDelay(500/portTICK_PERIOD_MS);
        //Wait to let other task execute
    }

}

void setup(){
    Serial.begin(115200);

    vTaskDelay(1000 / portTICK_PERIOD_MS);
    Serial.println();
    Serial.println("---FreeRTOS Deadlock Demo---");

    //create mutexes
    mutex_1 = xSemaphoreCreateMutex();
    mutex_2 = xSemaphoreCreateMutex();

    //Start task A (high priority)
    xTaskCreatePinnedToCore(doTaskA, "Task A", 1500, NULL, 2, NULL, app_cpu);

    //Start task B (low priority)
    xTaskCreatePinnedToCore(doTaskB, "Task B", 1500, NULL, 1, NULL, app_cpu);

    vTaskDelete(NULL);
}

void loop(){

}

在两个任务执行过程中到达第一个互斥体后,我的ESP32将自动重新启动,并显示以下消息:

代码语言:javascript
运行
复制
---FreeRTOS Deadlock Demo---
Task A took mutex 1
Task B took mutex 2
Task A timed out waiting for mutex 2. Trying again...

assert failed: xQueueGenericSend queue.c:832 (pxQueue->pcHead != ((void *)0) || pxQueue->u.xSemaphore.xMutexHolder == ((void *)0) || pxQueue->u.xSemaphore.xMutexHolder == xTaskGetCurrentTaskHandle())

我无法解释这个错误。但是,当我将互斥的定义更改为安装程序()中的二进制信号量时:

代码语言:javascript
运行
复制
//create mutexes
mutex_1 = xSemaphoreCreateBinary();
mutex_2 = xSemaphoreCreateBinary();

代码在ESP32中运行良好。有人能解释一下为什么会这样吗?非常感谢和抱歉,如果问题没有充分提出,因为这是我的第一个问题。

EN

回答 1

Stack Overflow用户

发布于 2022-11-04 18:24:45

信号量和互斥量之间的关键区别之一是所有权的概念。信号量,没有一条线拥有它们。即使优先级较低的线程已经获得信号量,高优先级线程也可以获得信号量。另一方面,互斥是由获取它们的线程拥有的,并且只能由该线程释放。

在上面的代码中,mutex_1是由Task获得的,mutex_2是由Task获得的。此时,Task试图获取mutex_2。当它是一个实际的互斥体时,Task无法获得它,因为它属于Task。但是,如果这是一个信号量,任务A可以从Task获得它,从而清除死锁。

这里的错误也与此有关。在任务A超时等待mutex_2之后,它开始释放互斥对象。它可以发布mutex_1没有问题,因为它拥有它。当它试图释放mutex_2时,它不能释放,因为它不是所有者。因此,操作系统抛出一个错误,因为一个任务不应该试图释放它不拥有的互斥对象。

如果您想更多地了解互斥和信号量之间的差异,可以查看这个文章

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73791395

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档