【FreeRTOS(二)】FreeRTOS新手入门——计数型信号量和二进制信号量的基本使用并附代码解析

简介: 【FreeRTOS(二)】FreeRTOS新手入门——计数型信号量和二进制信号量的基本使用并附代码解析

一、信号量概述

信号量(Semaphore):常用于任务的同步,通过该信号,就能够控制某个任务的执行。

信号量分两种:二进制信号量和计数型信号量。


二、计数型信号量

计数型信号量可以用于资源管理,允许多个任务获取信号量访问共享资源,但会限制任务的最大数目,访问的任务数达到可支持的最大数目时,会阻塞其他试图获取该信号量的任务,直到有任务释放了信号量。

例如:某个资源限定只能有3个任务访问,那么第4个任务访问的时候,会因为获取不到信号量而进入阻塞,等到有任务(比如任务1)释放掉该资源的时候,第4个任务才能获取到信号量从而进行资源的访问。其运行机制具体见下图


再举个形象点的例子:

有三个停车位,我停车,停车位-1,我开车走了,停车位+1。申请资源就是P操作,释放资源就是V操作



三、二进制信号量

二进制信号量和计数型信号量的唯一区别就是计数值的最大值被限定为1。

要想访问资源需要先“take”信号量,让计数值减1,用完资源后,“give”信号量,让计数值加1


四、信号量函数API

1、创建信号量

使用信号量之前,要先创建,得到一个句柄,使用信号量时,要使用句柄来表明使用哪个信号量。

二进制信号量和计数型信号量创建函数不同

创建二进制信号量函数原型:

静态创建:
SemaphoreHandle_t xSemaphoreCreateBinaryStatic( StaticSemaphore_t *pxSemaphoreBuffer );
动态创建:
SemaphoreHandle_t xSemaphoreCreateBinary( void );

创建计数型信号量函数原型:

静态创建:
SemaphoreHandle_t xSemaphoreCreateCountingStatic( UBaseType_t uxMaxCount, 
UBaseType_t uxInitialCount, StaticSemaphore_t *pxSemaphoreBuffer );
uxMaxCount: 最大计数值 
uxInitialCount: 初始计数值
pxSemaphoreBuffer: StaticSemaphore_t 结构体指针 
返回值: 返回句柄,非NULL表示成功

动态创建:
SemaphoreHandle_t xSemaphoreCreateCounting(UBaseType_t uxMaxCount, 
UBaseType_t uxInitialCount);

2、删除一个信号量

vSemaphoreDelete()用于删除一个信号量,包括二进制信号量、计数信号量、互斥量和递归互斥量。如果有任务阻塞在该信号量上,那么不要删除该信号量。

void vSemaphoreDelete(SemaphoreHandle_t xSemaphore)
xSemaphore——信号量句柄

3、信号量释放

xSemaphoreGive()是一个用于释放信号量的宏,真正的实现过程是调用消息队列通用发送函数。释放的信号量对象必须是已经被创建的。可以用于二进制信号量、计数型信号量、互斥信号量的释放。

BaseType_t xSemaphoreGive(SemaphoreHandle_t xSemaphore);

4、信号量获取

BaseType_t xSemaphoreTake(SemaphoreHandle_t xSemaphore, 
TickType_t xTicksToWait);

xTicksToWait——如果无法马上获得信号量,阻塞一会。0不阻塞,马上返回


五、示例代码

1、使用二进制信号量来同步

创建两个任务,一个用于释放信号量,一个用于获取信号量。

#include "FreeRTOS.h"
#include "task.h"
#include "xsc_test.h"
#include <stdio.h>
#include <kernel/dpl/ClockP.h>


StackType_t xscStack1[1024] __attribute__((aligned(32)));
StackType_t xscStack2[1024] __attribute__((aligned(32)));
StaticTask_t    xscTaskObj1;
StaticTask_t    xscTaskObj2;

void vSendTask(void *pvParameters)
{
    int cnt_ok = 0;
    int cnt_err = 0;
    const TickType_t xTicksToWait = pdMS_TO_TICKS(10UL);

    while (1)
    {
        for (int i = 0; i < 3; i++)
        {
            if (xSemaphoreGive(xBinarySemaphore) == pdTRUE)
            {
                DebugP_log("Give xBinarySemaphore %d time: OK\r\n", cnt_ok++);
            }
            else
            {
                DebugP_log("Give xBinarySemaphore %d time: ERR\r\n", cnt_err++);
            }
        }
        vTaskDelay(xTicksToWait);
    }
}

void vRecvTask(void *argc)
{
    int cnt_ok = 0;
    int cnt_err = 0;
    while (1)
    {
        if (xSemaphoreTake(xBinarySemaphore, portMAX_DELAY) == pdTRUE)
        {
            DebugP_log("Get xBinarySemaphore OK:%d\r\n", cnt_ok++);
        }
        else
        {
            DebugP_log("Get xBinarySemaphore ERR:%d\r\n", cnt_err++);
        }
    }
}

//Xsc_TestInit这个函数我在main函数调用了,就相当于main函数就行
void Xsc_TestInit(void)
{
    //创建二进制信号量
    xBinarySemaphore = xSemaphoreCreateBinary();    
    if (xBinarySemaphore != NULL)
    {
        //释放信号量
        xTaskCreateStatic(vSendTask, "vSendTask", 1024, NULL, 2, xscStack1, &xscTaskObj1);
        //获取信号量
        xTaskCreateStatic(vRecvTask, "vRecvTask", 1024, NULL, 1, xscStack2, &xscTaskObj2);
    }
    else
    {
        DebugP_log("xSemaphoreCreateBinary Failed!\r\n ");
    }
}


代码解释:

连续三次释放信号量,只有第一次能成功,然后发送任务阻塞,接收任务执行,获得信号量阻塞。在vTaskDelay退出之前都是运行的空闲任务。发送任务再次执行,连续三次释放信号量,只有第一次能成功,发送任务再阻塞,接受任务唤醒,打印OK。

demo演示:

2、使用计数型信号量

创建了一个计数型信号量,最大计数值为3,初始值为0,然后创建两个任务,一个用于释放信号量,一个用于获取信号量。

#include "FreeRTOS.h"
#include "task.h"
#include "xsc_test.h"
#include <stdio.h>
#include <kernel/dpl/ClockP.h>


StackType_t xscStack1[1024] __attribute__((aligned(32)));
StackType_t xscStack2[1024] __attribute__((aligned(32)));
StaticTask_t    xscTaskObj1;
StaticTask_t    xscTaskObj2;

void vSendTask(void *pvParameters)
{
    int cnt_ok = 0;
    int cnt_err = 0;
    const TickType_t xTicksToWait = pdMS_TO_TICKS(10UL);

    while (1)
    {
        for (int i = 0; i < 4; i++)
        {
            
            if (xSemaphoreGive(xCountingSemaphore) == pdTRUE)
            {
                DebugP_log("Give xCountingSemaphore %d time: OK\r\n", cnt_ok++);
            }
            else
            {
                DebugP_log("Give xCountingSemaphore %d time: ERR\r\n", cnt_err++);
            }
        }
        vTaskDelay(xTicksToWait);
    }
}

void vRecvTask(void *argc)
{
    int cnt_ok = 0;
    int cnt_err = 0;
    while (1)
    {
        if (xSemaphoreTake(xCountingSemaphore, portMAX_DELAY) == pdTRUE)
        {
            DebugP_log("Get xCountingSemaphore OK:%d\r\n", cnt_ok++);
        }
        else
        {
            DebugP_log("Get xCountingSemaphore ERR:%d\r\n", cnt_err++);
        }
    }
}

//Xsc_TestInit这个函数我在main函数调用了,就相当于main函数就行
void Xsc_TestInit(void)
{
    //创建计数型信号量
    xCountingSemaphore = xSemaphoreCreateCounting(3, 0);
    if (xCountingSemaphore != NULL)
    {
        //释放信号量
        xTaskCreateStatic(vSendTask, "vSendTask", 1024, NULL, 2, xscStack1, &xscTaskObj1);
        //获取信号量
        xTaskCreateStatic(vRecvTask, "vRecvTask", 1024, NULL, 1, xscStack2, &xscTaskObj2);
    }
    else
    {
        DebugP_log("xSemaphoreCreateBinary Failed!\r\n ");
    }
}


代码解释:

发送任务连续释放4个信号量,只有前面3次成功,第4次失败,阻塞,接受任务唤醒,得到三个信号量,阻塞。发送任务再次执行。

demo演示:

相关文章
|
1月前
|
存储 安全 程序员
|
1月前
|
缓存 关系型数据库 MySQL
这个错误提示表明Flink CDC在解析MySQL的二进制日志时,找不到对应表的TableMap事件。
这个错误提示表明Flink CDC在解析MySQL的二进制日志时,找不到对应表的TableMap事件。
157 2
|
1月前
|
算法 Java 编译器
☆打卡算法☆LeetCode 190. 颠倒二进制位 算法解析
☆打卡算法☆LeetCode 190. 颠倒二进制位 算法解析
|
API
STM32 FreeRTOS FreeRTOSConfig.h文件解析
STM32 FreeRTOS FreeRTOSConfig.h文件解析
73 0
|
算法
二进制运算解析
二进制运算解析
|
API 调度 芯片
FreeRTOS记录(三、RTOS任务调度原理解析_Systick、PendSV、SVC)
RTOS的任务调度原理和所使用的内核中断、寄存器息息相关 文中截图大多是《Cortex-M3与Cortex-M4权威指南》翻译版本里面的内容 需要对内核有一定的了解,本文尽量用简单的描述表达清楚 虽然是FreeRTOS的记录,但是原理上来说对于其他RTOS也是一样的!
1157 0
FreeRTOS记录(三、RTOS任务调度原理解析_Systick、PendSV、SVC)
|
XML Android开发 数据格式
Android逆向:二进制xml文件解析(Start Tag Chunk)
在Android中,xml文件经过编译后都是不可读的二进制文件。今天我们来解析一下这个二进制文件的内容,看看如何与我们的源码进行对应。
459 0
☆打卡算法☆LeetCode 67、二进制求和 算法解析
“给定两个二进制字符串,返回他们的和,用二进制形式。”
|
Android开发 Python
【Android 逆向】使用 Python 解析 ELF 文件 ( Capstone 反汇编 ELF 文件中的机器码数据 | 反汇编二进制机器码 | 打印反汇编数据 )
【Android 逆向】使用 Python 解析 ELF 文件 ( Capstone 反汇编 ELF 文件中的机器码数据 | 反汇编二进制机器码 | 打印反汇编数据 )
199 0
|
传感器 JSON 监控
设备上报二进制数据在 IoT 平台解析实践
设备上报二进制数据在 IoT 平台解析实践
11885 0

推荐镜像

更多