FreeRTOS-06-信号量

说明

本文仅作为学习FreeRTOS的记录文档,作为初学者肯定很多理解不对甚至错误的地方,望网友指正。
FreeRTOS是一个RTOS(实时操作系统)系统,支持抢占式、合作式和时间片调度。适用于微处理器或小型微处理器的实时应用。
本文档使用的FreeRTOS版本:FreeRTOS Kernel V10.4.1
参考文档:《FreeRTOS_Reference_Manual_V10.0.0.pdf》《FreeRTOS_Real_Time_Kernel-A_Hands-On_Tutorial_Guide.pdf》《STM32F4 FreeRTOS开发手册_V1.1.pdf》
参考视频:正点原子FreeRTOS手把手教学-基于STM32_哔哩哔哩_bilibili

9 信号量

信号量是操作系统重要的一部分,一般用来进行资源管理和任务同步,FreeRTOS信号量分为二值信号量、计数型信号量、互斥信号量和递归型信号量。

9.1 二值信号量

9.1.1 相关说明

二值信号量通常用于互斥访问或者同步。和互斥信号量的差别:互斥信号量有优先级继承,二值信号量没有优先级继承,所有二值信号量适用于同步,而互斥信号量适用于互斥访问。

和队列一样,信号量API函数允许设置一个阻塞时间,阻塞时间是当任务获得信号的时候由于信号量无效从而导致任务进行阻塞态的最大时钟节拍数,当信号量有效时高优先级任务就会解除阻塞状态。

二值信号量就是只有一个队列项的队列,所以这个队列要么满的,要么空的。二值信号量的工作过程如下:

(1)二值信号量无效,任务阻塞等待信号量

image-20210925202005105

(2)中断发生,释放了信号量

image-20210925202021317

(3)任务获取信号量成功,从阻塞状态解除

image-20210925202037726

(4)任务再次进入阻塞态,等待信号量

image-20210925202146779

完整的一次流程如下:

img

9.1.2 相关函数

(1)动态创建信号量

函数原型:

#include "FreeRTOS.h"
#include "semphr.h"
SemaphoreHandle_t xSemaphoreCreateBinary( void );

函数描述:创建一个二值信号量,并返回信号量句柄。每一个信号量需要一个内存空间来存放信号量状态。这个函数的创建的信号量空间由FreeRTOS自动分配。信号量创建之后是空的,任务这时候是无法获得的。

函数参数:

返回值:NULL:创建失败。其他值:创建成功的二值信号量的句柄

(2)静态创建信号量

函数原型:

#include “FreeRTOS.h”
#include “semphr.h”
SemaphoreHandle_t xSemaphoreCreateBinaryStatic( StaticSemaphore_t *pxSemaphoreBuffer );

函数描述:创建一个二值信号量,并返回信号量句柄。每一个信号量需要一个内存空间来存放信号量状态。这个函数的创建的信号量空间由用户指定。信号量创建之后是空的,任务这时候是无法获得的。

函数参数:pxSemaphoreBuffer:指向StaticSemaphore_t类型的变量,这个变量用来保存信号量的状态。

返回值:NULL:创建失败。其他值:创建成功的二值信号量的句柄

(3)任务级释放信号量

函数原型:

#include “FreeRTOS.h”
#include “semphr.h”
BaseType_t xSemaphoreGive( SemaphoreHandle_t xSemaphore );

函数描述:释放信号量之前,信号量必须已经被创建了。

函数参数:xSemaphore:要释放的信号量句柄

返回值:pdPASS:信号量释放成功。pdFAIL:信号量释放失败。

(4)中断级释放信号量

函数原型:

#include “FreeRTOS.h”
#include “semphr.h”
BaseType_t xSemaphoreGiveFromISR( SemaphoreHandle_t xSemaphore,
                                 BaseType_t *pxHigherPriorityTaskWoken );

函数描述:中断级释放信号量函数,在中断处理函数中使用。

函数参数:xSemaphore:要释放的信号量句柄;

pxHigherPriorityTaskWoken:标记退出此函数是否进行任务切换,此值为pdTRUE的时候在退出中断函数之前要进行一次任务切换。

返回值:pdPASS:信号量释放成功。errQUEUE_FULL:信号量释放失败,信号量已经被释放了。

(5)任务级获取信号量

函数原型:

#include “FreeRTOS.h”
#include “semphr.h”
BaseType_t xSemaphoreTake( SemaphoreHandle_t xSemaphore,
                          TickType_t xTicksToWait );

函数描述:获取信号量之前,信号量必须已经被创建了。

函数参数:xSemaphore:要获取的信号量句柄;

xTicksToWait:当任务无法获取到信号量,任务最大的保持阻塞的时间。如果为0,任务无法获得信号量时将立即返回。阻塞时间指的时时钟滴答数,所以阻塞的时间大小取决于系统频率,可以使用pdMS_TO_TICKS() 宏来指定阻塞多少毫秒。如果为portMAX_DELAY,任务将一直等待。

返回值:pdPASS:信号量获取成功。pdFAIL:信号量获取失败。

(6)中断级获取信号量

函数原型:

#include “FreeRTOS.h”
#include “queue.h”
BaseType_t xSemaphoreTakeFromISR( SemaphoreHandle_t xSemaphore,
                                 signed BaseType_t *pxHigherPriorityTaskWoken );

函数描述:在中断服务函数中获取信号量。

函数参数:xSemaphore:要获取的信号量句柄;

pxHigherPriorityTaskWoken:标记退出此函数后是否进行任务切换,此值为pdTRUE的时候在退出中断函数之前要进行一次任务切换。

返回值:pdPASS:信号量获取成功。pdFAIL:信号量获取失败。

9.1.3 操作实验

实验目的:使用二值信号量完成任务间的同步

实验设计:任务task00定时释放二值信号量,任务task01获取二值信号量,接收到信号量就进行相应的动作。

测试代码:

/* task00 info */
configSTACK_DEPTH_TYPE Task00_STACK_SIZE = 5;
UBaseType_t  Task00_Priority = 1;
TaskHandle_t Task00_xHandle;

/* task01 info */
configSTACK_DEPTH_TYPE Task01_STACK_SIZE = 5;
UBaseType_t  Task01_Priority = 2;
TaskHandle_t Task01_xHandle;

//二值信号量
SemaphoreHandle_t BinarySemaphore;

void vTask00_Code(void *para)
{
    static unsigned int cnt = 0;
    BaseType_t err = pdTRUE;
    for (;;)
    {
        PRINT(" task00 cnt %u...", cnt++);
        err = xSemaphoreGive(BinarySemaphore);
        if (err != pdTRUE)
            PRINT("BinarySemaphore give failed!\n");
        vTaskDelay(2000);
    }
}

void vTask01_Code(void *para)
{
    static unsigned int cnt = 0;
    BaseType_t err = pdTRUE;
    for (;;)
    {
        xSemaphoreTake(BinarySemaphore, portMAX_DELAY);
        PRINT(" task01 cnt %u...", cnt++);
        vTaskDelay(500);
    }
}

void test_BinarySemaphore()
{
    BinarySemaphore = xSemaphoreCreateBinary();
    
    if (xTaskCreate(vTask00_Code, "task00 task", 
        Task00_STACK_SIZE, NULL, Task00_Priority,
        &Task00_xHandle) != pdPASS)
    {
        PRINT("creat task00 failed!\n");
    }
    
    if (xTaskCreate(vTask01_Code, "task01 task", 
        Task01_STACK_SIZE, NULL, Task01_Priority,
        &Task01_xHandle) != pdPASS)
    {
        PRINT("creat task01 failed!\n");
    }
}

void creat_task(void)
{
    test_BinarySemaphore();
//    test_queue();
}

编译,运行:

$ ./build/freertos-simulator 
 task00 cnt 0...
 task01 cnt 0...
 task00 cnt 1...
 task01 cnt 1...
 task00 cnt 2...
 task01 cnt 2...

可以看出,任务task01等到了信号量之后才会执行。

接着,将获取信号量函数xSemaphoreTake的阻塞时间改为0,也就是没获取到信号量,立即返回。

void vTask01_Code(void *para)
{
    static unsigned int cnt = 0;
    BaseType_t err = pdTRUE;
    for (;;)
    {
        xSemaphoreTake(BinarySemaphore, 0);
        PRINT(" task01 cnt %u...", cnt++);
        vTaskDelay(500);
    }
}

编译,运行:

$ ./build/freertos-simulator 
 task01 cnt 0...
 task00 cnt 0...
 task01 cnt 1...
 task01 cnt 2...
 task01 cnt 3...
 task01 cnt 4...
 task00 cnt 1...

可以看出,任务task01不会等待信号量,而是继续执行。

9.1.4 优先级反转

使用二值信号量会出现优先级反转的问题,优先级反转在可剥夺内核中是常见的,但在实时系统中不允许出现这种现象。

image-20210925222858088

上述图中,高任务H会晚于低优先级任务M执行,这就发生了优先级反转。

优先级反转实验设计:

实验设计:创建三个任务,高优先级任务获取二值信号量,获取成功后进行相应的处理,处理完之后释放信号量;中优先级任务简单运行;低优先级任务和高优先级任务一样,会获取二值信号量,获取成功后进行相应处理。

测试代码:

configSTACK_DEPTH_TYPE TaskLow_STACK_SIZE = 5;
UBaseType_t  TaskLow_Priority = 2;
TaskHandle_t TaskLow_xHandle;

configSTACK_DEPTH_TYPE TaskMiddle_STACK_SIZE = 5;
UBaseType_t  TaskMiddle_Priority = 3;
TaskHandle_t TaskMiddle_xHandle;

configSTACK_DEPTH_TYPE TaskHigh_STACK_SIZE = 5;
UBaseType_t  TaskHigh_Priority = 4;
TaskHandle_t TaskHigh_xHandle;


//二值信号量
SemaphoreHandle_t BinarySemaphore;

void vTaskLow_Code(void *para)
{
    static unsigned int times = 0;
    BaseType_t err = pdTRUE;
    for (;;)
    {
        xSemaphoreTake(BinarySemaphore, portMAX_DELAY);
        PRINT(" low task running");
        for (times = 0; times < 20000000; times++)
            taskYIELD();
        err = xSemaphoreGive(BinarySemaphore);
        if (err != pdTRUE)
            PRINT("BinarySemaphore give failed!");
        vTaskDelay(1000);
    }
}

void vTaskMiddle_Code(void *para)
{
    for (;;)
    {
        PRINT(" task middle running");
        vTaskDelay(1000);
    }
}

void vTaskHigh_Code(void *para)
{
    for (;;)
    {
        vTaskDelay(500);
        PRINT(" task high Pend Sem");
        xSemaphoreTake(BinarySemaphore, portMAX_DELAY);
        PRINT(" task high running!");
        xSemaphoreGive(BinarySemaphore);
        vTaskDelay(500);
    }
}


void test_BinarySemaphore()
{
    taskENTER_CRITICAL();
    BinarySemaphore = xSemaphoreCreateBinary();
    if (BinarySemaphore != NULL)
        xSemaphoreGive(BinarySemaphore);
    
    if (xTaskCreate(vTaskLow_Code, "taskLow task", 
        TaskLow_STACK_SIZE, NULL, TaskLow_Priority,
        &TaskLow_xHandle) != pdPASS)
    {
        PRINT("creat taskLow failed!\n");
    }
    
    if (xTaskCreate(vTaskMiddle_Code, "taskMiddle task", 
        TaskMiddle_STACK_SIZE, NULL, TaskMiddle_Priority,
        &TaskMiddle_xHandle) != pdPASS)
    {
        PRINT("creat taskMiddle failed!\n");
    }

    if (xTaskCreate(vTaskHigh_Code, "taskHigh task", 
        TaskHigh_STACK_SIZE, NULL, TaskHigh_Priority,
        &TaskHigh_xHandle) != pdPASS)
    {
        PRINT("creat taskHigh failed!\n");
    }
    taskEXIT_CRITICAL();
}


void creat_task(void)
{
    test_BinarySemaphore();
}

编译、运行:

$ ./build/freertos-simulator 
 task middle running
 low task running
 task high Pend Sem
 task middle running
 task middle running
 task middle running
 task middle running
 task middle running
 task middle running
 task middle running
 task middle running
 task middle running
 task middle running
 task middle running
 task middle running
 task middle running
 task middle running
 task middle running
 task middle running
 task middle running
 task middle running
 task middle running
 task middle running
 task middle running
 task middle running
 task middle running
 task middle running
 task middle running
 task middle running
 task middle running
 task middle running
 task high running!
 task middle running
 task high Pend Sem
 task high running!
 low task running
 task middle running

可以看出了优先级反转,中优先级任务比高优先级任务先执行。

9.2 计数型信号量

计数型信号量也叫数值型信号量,其实质是长度大于1的队列。

主要用于两个场景:

1、事件计数:在这个场景中,每次事件发生时就在事件处理函数中释放信号量,其他任务获取信号量来处理事件。这种场合计数型信号量初始计数值为0。

2、资源管理:在这个场景中,信号量代表当前可用的资源数量。一个任务想要获取资源的使用权,必须先获得信号量,信号量获取成功信号量就会减1,当信号量为0时就没有信号量了。当一个任务使用完信号量之后要释放信号量。这个场景中,信号量的初始值就是资源的数量。

9.2.1 相关函数

(1)动态创建函数

函数原型:

#include “FreeRTOS.h”
#include “semphr.h”
SemaphoreHandle_t xSemaphoreCreateCounting( UBaseType_t uxMaxCount,
                                           UBaseType_t uxInitialCount );

函数描述:创建一个计数型信号量,返回信号量的句柄。信号量的内存空间由系统指定。

函数参数:uxMaxCount:计数信号量的最大计数值,当信号量值等于这个值的时候释放信号量就会失败。

uxInitialCount:计数信号量初始值。

返回值:NULL:计数信号量创建失败;其他值:计数信号量创建成功,返回计数信号量句柄。

(2)静态创建函数

函数原型:

#include “FreeRTOS.h”
#include “semphr.h”
SemaphoreHandle_t xSemaphoreCreateCountingStatic( UBaseType_t uxMaxCount,
                                                 UBaseType_t uxInitialCount,
                                                 StaticSemaphore_t pxSempahoreBuffer );

函数描述:创建一个计数型信号量,返回信号量的句柄。信号量的内存空间由用户指定。

函数参数:uxMaxCount:计数信号量的最大计数值,当信号量值等于这个值的时候释放信号量就会失败。

uxInitialCount:计数信号量初始值。

pxSempahoreBuffer:指向StaticSemaphore_t类型的变量,用于保存信号量结构体。

返回值:NULL:计数信号量创建失败;其他值:计数信号量创建成功,返回计数信号量句柄。

(2)释放和获取函数

释放和获取函数和二值信号量的一样,参见9.1.2小节。

9.2.2 操作实验

实验目的:学习计数型信号量的使用方法。

实验设计:主函数中创建一个计数型信号量,计数值为10,初始化计数值为0,然后创建两个任务,任务task00释放信号量,任务task01获取信号量。

测试代码:

/* task00 info */
configSTACK_DEPTH_TYPE Task00_STACK_SIZE = 5;
UBaseType_t  Task00_Priority = 1;
TaskHandle_t Task00_xHandle;

/* task01 info */
configSTACK_DEPTH_TYPE Task01_STACK_SIZE = 5;
UBaseType_t  Task01_Priority = 3;
TaskHandle_t Task01_xHandle;

//计数型信号量
SemaphoreHandle_t CountSemaphore;

void vTask00_Code(void *para)
{
    static unsigned int cnt = 0;
    BaseType_t err = pdTRUE;
    for (;;)
    {
        PRINT(" task00 cnt %u...", cnt++);
        err = xSemaphoreGive(CountSemaphore);
        if (err != pdTRUE)
            PRINT("BinarySemaphore give failed!\n");
        vTaskDelay(200);
        if (cnt == 4)
            vTaskDelete(Task00_xHandle);
    }
}

void vTask01_Code(void *para)
{
    static unsigned int cnt = 0;
    BaseType_t err = pdTRUE;
    for (;;)
    {
        xSemaphoreTake(CountSemaphore, portMAX_DELAY);
        PRINT(" task01 cnt %u...", cnt++);
        vTaskDelay(1000);
    }
}

void test_CountSemaphore()
{
    CountSemaphore = xSemaphoreCreateCounting(10, 0);
    
    if (xTaskCreate(vTask00_Code, "task00 task", 
        Task00_STACK_SIZE, NULL, Task00_Priority,
        &Task00_xHandle) != pdPASS)
    {
        PRINT("creat task00 failed!\n");
    }
    
    if (xTaskCreate(vTask01_Code, "task01 task", 
        Task01_STACK_SIZE, NULL, Task01_Priority,
        &Task01_xHandle) != pdPASS)
    {
        PRINT("creat task01 failed!\n");
    }
}


void creat_task(void)
{
    test_CountSemaphore();
}

编译、运行:

$ ./build/freertos-simulator 
 task00 cnt 0...
 task01 cnt 0...
 task00 cnt 1...
 task00 cnt 2...
 task00 cnt 3...
 task01 cnt 1...
 task01 cnt 2...
 task01 cnt 3...

可以看出,共释放了4个信号量,任务task1执行了4次。

9.3 互斥信号量

9.3.1 相关说明

互斥信号量其实就是一个拥有优先级继承的二值信号量,在同步任务应用中二值信号量最合适,互斥信号量适用于那些需要互斥访问的应用中。

互斥信号量和二值信号量使用相同的API函数,所以互斥信号量也可以设置阻塞时间,不同于二值信号量的是互斥信号量具有优先级继承关系。当一个互斥信号量正在被低优先级的任务使用,而此时有个高优先级的任务也尝试获取这个信号量的话就会被阻塞。不过高优先级的任务会将低优先级的任务的优先级提升到与自己相同的优先级,这个过程就是优先级继承。优先级继承尽可能的降低了高优先级任务处于阻塞态的时间,并且将“优先级翻转”的影响降低到了最低。

优先级继承并不能完全的消除优先级翻转,只是尽可能降低了优先级翻转带来的影响。

互斥信号量不能用于中断服务函数中,原因如下:

1、互斥信号量有优先级继承的机制,所以只能用在任务中,不能用于中断服务函数;

2、中断服务函数中不能因为要等待互斥信号量而设置阻塞时间进入阻塞态。

9.3.2 相关函数

(1)动态创建函数

函数原型:

#include “FreeRTOS.h”
#include “semphr.h”
SemaphoreHandle_t xSemaphoreCreateMutex( void );

函数描述:创建一个互斥型信号量,返回信号量的句柄。信号量的内存空间由系统指定。

函数参数:

返回值:NULL:信号量创建失败;其他值:信号量创建成功,返回信号量句柄。

(2)静态创建函数

函数原型:

#include “FreeRTOS.h”
#include “semphr.h”
SemaphoreHandle_t xSemaphoreCreateMutexStatic( 
    StaticSemaphore_t *pxMutexBuffer );

函数描述:创建一个互斥型信号量,返回信号量的句柄。信号量的内存空间由用户指定。

函数参数:pxMutexBuffer:指向StaticSemaphore_t类型的变量,用于保存信号量结构体。

返回值:NULL:信号量创建失败;其他值:信号量创建成功,返回信号量句柄。

(3)释放和获取函数

释放和获取函数和二值信号量的一样,参见9.1.2小节。

9.3.3 操作实验

实验目的:学习互斥型信号量的使用方法。

实验设计:本实验在“9.1.4 优先级反转”的基础上完成,只是将其中二值信号量更换为互斥信号量。

测试代码:

configSTACK_DEPTH_TYPE TaskLow_STACK_SIZE = 5;
UBaseType_t  TaskLow_Priority = 2;
TaskHandle_t TaskLow_xHandle;

configSTACK_DEPTH_TYPE TaskMiddle_STACK_SIZE = 5;
UBaseType_t  TaskMiddle_Priority = 3;
TaskHandle_t TaskMiddle_xHandle;

configSTACK_DEPTH_TYPE TaskHigh_STACK_SIZE = 5;
UBaseType_t  TaskHigh_Priority = 4;
TaskHandle_t TaskHigh_xHandle;

SemaphoreHandle_t MutexSemaphore;

void vTaskLow_Code(void *para)
{
    static unsigned int times = 0;
    BaseType_t err = pdTRUE;
    for (;;)
    {
        xSemaphoreTake(MutexSemaphore, portMAX_DELAY);
        PRINT(" low task running");
        for (times = 0; times < 20000000; times++)
            taskYIELD();
        err = xSemaphoreGive(MutexSemaphore);
        if (err != pdTRUE)
            PRINT("BinarySemaphore give failed!");
        vTaskDelay(1000);
    }
}

void vTaskMiddle_Code(void *para)
{
    for (;;)
    {
        PRINT(" task middle running");
        vTaskDelay(1000);
    }
}

void vTaskHigh_Code(void *para)
{
    for (;;)
    {
        vTaskDelay(500);
        PRINT(" task high Pend Sem");
        xSemaphoreTake(MutexSemaphore, portMAX_DELAY);
        PRINT(" task high running!");
        xSemaphoreGive(MutexSemaphore);
        vTaskDelay(500);
    }
}


void test_MutexSemaphore()
{
    taskENTER_CRITICAL();
    MutexSemaphore = xSemaphoreCreateMutex();
    if (MutexSemaphore != NULL)
        xSemaphoreGive(MutexSemaphore);
    
    if (xTaskCreate(vTaskLow_Code, "taskLow task", 
        TaskLow_STACK_SIZE, NULL, TaskLow_Priority,
        &TaskLow_xHandle) != pdPASS)
    {
        PRINT("creat taskLow failed!\n");
    }
    
    if (xTaskCreate(vTaskMiddle_Code, "taskMiddle task", 
        TaskMiddle_STACK_SIZE, NULL, TaskMiddle_Priority,
        &TaskMiddle_xHandle) != pdPASS)
    {
        PRINT("creat taskMiddle failed!\n");
    }

    if (xTaskCreate(vTaskHigh_Code, "taskHigh task", 
        TaskHigh_STACK_SIZE, NULL, TaskHigh_Priority,
        &TaskHigh_xHandle) != pdPASS)
    {
        PRINT("creat taskHigh failed!\n");
    }
    taskEXIT_CRITICAL();
}


void creat_task(void)
{
    test_MutexSemaphore();
}

编译,运行,测试结果如下:

$ ./build/freertos-simulator 
 task middle running
 low task running
 task high Pend Sem  //此时信号量被任务low_task占用,会一直等待任务low_task释放信号量。
 task high running!  //高优先级任务等待一段时间才运行,但中优先级任务不会运行。
 task middle running
 task high Pend Sem
 task high running!
 task middle running
 low task running
 task high Pend Sem

9.4 递归互斥信号量

9.4.1 相关说明

递归互斥信号量可以看作是一个特殊的互斥信号量,已经获取了互斥信号量的任务就不能再次获取这个信号量,但是递归信号量不同,已经获取了递归互斥信号量的任务可以再次获取这个信号量,而且次数不限。任务获取了多少次递归信号量就要释放多少次。

递归互斥信号量也有优先级继承机制,所以当任务使用完递归信号量之后一定要释放。

同互斥信号量一样,递归信号量也不能用在中断服务函数中:

1、由于优先级继承的存在,就限定了递归互斥信号量只能用在任务中,不能用在中断函数中。

2、中断服务函数不能设置阻塞时间。

9.4.2 相关函数

(1)动态创建函数

函数原型:

#include “FreeRTOS.h”
#include “semphr.h”
SemaphoreHandle_t xSemaphoreCreateRecursiveMutex( void );

函数描述:创建一个递归互斥信号量,返回信号量的句柄。信号量的内存空间由系统指定。

函数参数:

返回值:NULL:信号量创建失败;其他值:信号量创建成功,返回信号量句柄。

(2)静态创建函数

函数原型:

#include “FreeRTOS.h”
#include “semphr.h”
SemaphoreHandle_t xSemaphoreCreateRecursiveMutex(
    StaticSemaphore_t pxMutexBuffer );

函数描述:创建一个递归互斥信号量,返回信号量的句柄。信号量的内存空间由用户指定。

函数参数:pxMutexBuffer:指向StaticSemaphore_t类型的变量,用于保存信号量结构体。

返回值:NULL:信号量创建失败;其他值:信号量创建成功,返回信号量句柄。

(3)释放递归型互斥信号量函数

函数原型:

#include “FreeRTOS.h”
#include “semphr.h”
BaseType_t xSemaphoreGiveRecursive( SemaphoreHandle_t xMutex );

函数描述:释放递归互斥信号量。

函数参数:xMutex:信号量句柄。

返回值:pdPASS:释放信号量成功;pdFAIL:释放信号量失败。

(4)获取递归型互斥信号量函数

函数原型:

#include “FreeRTOS.h”
#include “semphr.h”
BaseType_t xSemaphoreTakeRecursive( SemaphoreHandle_t xMutex,
TickType_t xTicksToWait );

函数描述:获取递归互斥信号量。

函数参数:xMutex:信号量句柄。xTicksToWait:阻塞时间。

返回值:pdPASS:获取信号量成功;pdFAIL:获取信号量失败。

9.4.3 操作实验

实验目的:学习递归互斥型信号量的使用方法。

实验设计:创建一个任务,任务处理函数中每次获取递归互斥信号量三次,释放信号量三次。

测试代码:

configSTACK_DEPTH_TYPE Task0_STACK_SIZE = 5;
UBaseType_t  Task0_Priority = 2;
TaskHandle_t Task0_xHandle;

SemaphoreHandle_t RecursiveMutexSemaphore;

void vTask0_Code(void *para)
{
    for (;;)
    {
        if (xSemaphoreTakeRecursive(RecursiveMutexSemaphore, 10) == pdTRUE) {
            xSemaphoreTakeRecursive(RecursiveMutexSemaphore, 10);
            xSemaphoreTakeRecursive(RecursiveMutexSemaphore, 10);
            PRINT("RecursiveMutexSemaphore take!");
            xSemaphoreGiveRecursive(RecursiveMutexSemaphore);
            xSemaphoreGiveRecursive(RecursiveMutexSemaphore);
            xSemaphoreGiveRecursive(RecursiveMutexSemaphore);
            PRINT("RecursiveMutexSemaphore give!");
        }
        vTaskDelay(1000);
    }
}

void test_RecursiveMutexSemaphore()
{
    taskENTER_CRITICAL();
    RecursiveMutexSemaphore = xSemaphoreCreateRecursiveMutex();
    if (RecursiveMutexSemaphore != NULL) {
        xSemaphoreGiveRecursive(RecursiveMutexSemaphore);
        xSemaphoreGiveRecursive(RecursiveMutexSemaphore);
        xSemaphoreGiveRecursive(RecursiveMutexSemaphore);
    }
    if (xTaskCreate(vTask0_Code, "taskLow task", 
        Task0_STACK_SIZE, NULL, Task0_Priority,
        &Task0_xHandle) != pdPASS)
    {
        PRINT("creat taskLow failed!\n");
    }
    taskEXIT_CRITICAL();
}


void creat_task(void)
{
    test_RecursiveMutexSemaphore();
}

编译、运行,结果如下:

$ ./build/freertos-simulator 
RecursiveMutexSemaphore take!
RecursiveMutexSemaphore give!
RecursiveMutexSemaphore take!
RecursiveMutexSemaphore give!
posted @ 2021-09-25 22:41  zhengcixi  阅读(128)  评论(0编辑  收藏  举报
回到顶部