FreeRTOS实时操作系统信号量基础

下面我将通过以下几个方面,来详细讲解“FreeRTOS实时操作系统信号量基础”的完整攻略:

  1. 信号量是什么
  2. FreeRTOS的信号量及其基础API
  3. 信号量的使用示例说明
  4. 进一步扩展: 二值信号量和计数信号量

1. 信号量是什么

信号量是一种基本的同步机制,在多任务并发执行、共享资源时起到重要作用。它可以控制多个任务对共享资源的访问顺序,保证每个任务能够按照一定的顺序获取共享资源而不会冲突,从而保证系统的正确运行。

2. FreeRTOS的信号量及其基础API

FreeRTOS提供了两种类型的信号量:二值信号量和计数信号量。

二值信号量的取值范围只有两个:0和1。该类型的信号量通常用于同步任务之间的行为,比如某个任务执行完了一个关键操作后通知其他任务开始执行某个操作。

计数信号量的取值范围可以是任意正整数。该类型的信号量通常用于控制资源访问的数量,比如限制同时只有两个任务可以对某个资源进行访问。

以下是FreeRTOS提供的信号量API:

  • xSemaphoreCreateBinary():创建一个二值信号量
  • xSemaphoreCreateCounting(uxMaxCount, uxInitialCount):创建一个计数信号量,uxMaxCount表示允许的最大值,uxInitialCount表示初始值
  • xSemaphoreTake(xSemaphore, xBlockTime):指定一个信号量,该函数会尝试获取该信号量。如果信号量的取值为0,取值操作将会阻塞(如果指定了阻塞时间xBlockTime则会阻塞一段时间),直到信号量的取值为1或其他任务释放该信号量
  • xSemaphoreGive(xSemaphore):将一个信号量的值加1,相当于释放该信号量
  • xSemaphoreGiveFromISR(xSemaphore, pxHigherPriorityTaskWoken):和xSemaphoreGive的差不多,只是该函数可以在中断里面使用。如果该函数使得某个任务的优先级变得比当前任务高,那么参数pxHigherPriorityTaskWoken将被设置为非零值

3. 信号量的使用示例说明

我们先看一个简单的二值信号量的使用示例:

#include "FreeRTOS.h"
#include "semphr.h"

SemaphoreHandle_t s_binary;

void task_A(void* params) {
    while (1) {
        // 尝试获取二值信号量
        if (xSemaphoreTake(s_binary, portMAX_DELAY) == pdTRUE) {
            // 用打印语句替代具体的任务处理
            printf("Task A Acquire Binary Semaphore.\r\n");
            vTaskDelay(pdMS_TO_TICKS(1000));
            // 释放二值信号量
            xSemaphoreGive(s_binary);
        }
    }
}

void task_B(void* params) {
    while (1) {
        // 尝试获取二值信号量
        if (xSemaphoreTake(s_binary, portMAX_DELAY) == pdTRUE) {
            // 用打印语句替代具体的任务处理
            printf("Task B Acquire Binary Semaphore.\r\n");
            vTaskDelay(pdMS_TO_TICKS(1000));
            // 释放二值信号量
            xSemaphoreGive(s_binary);
        }
    }
}

int main() {
    // 创建一个二值信号量
    s_binary = xSemaphoreCreateBinary();

    xTaskCreate(task_A, "Task A", 512, NULL, 1, NULL);
    xTaskCreate(task_B, "Task B", 512, NULL, 2, NULL);
    // 启动调度器
    vTaskStartScheduler();

    return 0;
}

在这个示例中,我们创建了一个二值信号量s_binary,两个任务(task_Atask_B)将会通过该信号量进行同步。每个任务的执行方式类似,大致的流程如下:

  1. 尝试获取二值信号量s_binary
  2. 如果获取成功,说明该任务可以开始执行,用打印语句替代具体的任务处理,等待1秒;
  3. 释放二值信号量s_binary

从示例中我们可以看出,只要二值信号量被某个任务获取,其他任务就无法获取该信号量,直到该任务将其释放。

我们再来看一个计数信号量的使用示例:

#include "FreeRTOS.h"
#include "semphr.h"

SemaphoreHandle_t s_counting;

void task_C(void* params) {
    while (1) {
        // 尝试获取计数信号量
        if (xSemaphoreTake(s_counting, portMAX_DELAY) == pdTRUE) {
            // 用打印语句替代具体的任务处理
            printf("Task C Acquire Counting Semaphore.\r\n");
            vTaskDelay(pdMS_TO_TICKS(1000));
            // 释放计数信号量
            xSemaphoreGive(s_counting);
        }
    }
}

void task_D(void* params) {
    while (1) {
        // 尝试获取计数信号量
        if (xSemaphoreTake(s_counting, portMAX_DELAY) == pdTRUE) {
            // 用打印语句替代具体的任务处理
            printf("Task D Acquire Counting Semaphore.\r\n");
            vTaskDelay(pdMS_TO_TICKS(1000));
            // 释放计数信号量
            xSemaphoreGive(s_counting);
        }
    }
}

int main() {
    // 创建一个计数信号量,允许的最大值为3,初始值为2
    s_counting = xSemaphoreCreateCounting(3, 2);

    xTaskCreate(task_C, "Task C", 512, NULL, 1, NULL);
    xTaskCreate(task_D, "Task D", 512, NULL, 2, NULL);
    // 启动调度器
    vTaskStartScheduler();

    return 0;
}

在这个示例中,我们创建了一个计数信号量s_counting,两个任务(task_Ctask_D)将会通过该信号量进行同步。s_counting的最大值为3,初始值为2,从而保证同时最多只有两个任务可以获取该信号量。每个任务的执行方式类似,大致的流程如下:

  1. 尝试获取计数信号量s_counting
  2. 如果获取成功,说明该任务可以开始执行,用打印语句替代具体的任务处理,等待1秒;
  3. 释放计数信号量s_counting

从示例中我们可以看出,只要计数信号量$s_counting$还没有达到最大值,就可以任意多个任务获取该信号量,而达到最大值后,其他任务就无法获取该信号量,直到某个任务释放该信号量。

4. 进一步扩展: 二值信号量和计数信号量

在FreeRTOS中,二值信号量和计数信号量只是信号量的两种常见类型。如果我们需要更复杂的同步机制,可以通过扩展信号量来实现。以下是常见的信号量扩展方法:

  1. 二进制资源信号量(Binary Resource Semaphore):可以用于共享的硬件资源或软件资源等。在一些嵌入式系统中,CPU的某个时钟信号可能需要被多个模块共享,因此需要使用二进制资源信号量来管理共享。
  2. 优先级继承信号量(Priority Inheritance Semaphore):可以解决“优先级反转”(Priority Inversion)的问题。比如,如果高优先级任务需要等待低优先级任务占用的共享资源,而低优先级任务又正在等待其他资源,这时候就需要使用优先级继承信号量来提高高优先级任务的优先级,并且防止低优先级任务“抢占”共享资源而导致高优先级任务无限等待的问题。
  3. 读写信号量(Read-Write Semaphore):可以实现读者-写者问题。在一些多线程程序中,可能需要实现读操作和写操作的互斥,写者优先于读者、读者与读者之间不互斥等。这种情况下,可以使用读写信号量来解决问题。

扩展信号量需要根据具体情况,选择不同的实现方法。但基本的原则是要保证信号量的安全操作,避免死锁、优先级反转等问题的产生。

以上就是关于“FreeRTOS实时操作系统信号量基础”的完整攻略。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:FreeRTOS实时操作系统信号量基础 - Python技术站

(0)
上一篇 2023年6月27日
下一篇 2023年6月27日

相关文章

  • JAVA基础之注解与反射的使用方法和场景

    JAVA基础之注解与反射的使用方法和场景 1. 注解(Annotation)的概述 注解是一种用于为程序元素(类、方法、字段等)添加元数据的方式。它们提供了一种在代码中添加补充信息的简洁且灵活的方式。在Java中,注解以@符号开头,可以用于提供编译时的信息、运行时的行为以及生成文档等。 2. 注解的使用方法 2.1 定义注解 在Java中,我们可以使用@in…

    other 2023年8月6日
    00
  • 在双硬盘上安装独立32位和64位双系统

    在双硬盘上安装独立32位和64位双系统攻略 准备工作 确保你有两个硬盘可用,一个用于安装32位系统,另一个用于安装64位系统。 下载所需的32位和64位操作系统的安装镜像文件,并将其保存到可访问的位置。 安装32位系统 将32位操作系统的安装镜像文件写入一个可启动的USB闪存驱动器或光盘。 将32位系统的安装媒介插入计算机,并重启计算机。 在计算机启动时,按…

    other 2023年7月28日
    00
  • 启动avahi-daemon

    当然,我很乐意为您提供有关“启动avahi-daemon”的完整攻略。以下是详细的步骤和两个示例: 1 启动avahi-daemon avahi-daemon是一个开源的零配置网络服务发现工具,它可以自动发现网络上的服务和设备。以下是启动avahi-daemon的步骤: 1.1 安装avahi-daemon 首先,您需要在Linux系统中安装avahi-da…

    other 2023年5月6日
    00
  • 关于vb.net:if语句单行用法

    关于VB.NET: If语句单行用法 在VB.NET中,If语句是一种常用的条件语句,它可以根据条件执行不同的代码块。除了常规的多行If语句,VB.NET还提供了单行If语句的用法,可以帮助开发人员更快地编写代码。以下是关于VB.NET: If语句单行用法的完整攻略,包括常见问题和两个示例说明。 常见问题 1. 什么是VB.NET If语句? If语句是一种…

    other 2023年5月9日
    00
  • android9.0 默认apk权限添加方法

    Android 9.0 默认APK权限添加方法 在Android 9.0及以上版本中,应用默认不再具有一些敏感权限,需要在运行时动态请求用户授权。本攻略将详细讲解如何在Android 9.0中添加默认APK权限。 1. 在AndroidManifest.xml中声明权限 首先,在你的应用的AndroidManifest.xml文件中添加需要的权限声明。例如,…

    other 2023年10月13日
    00
  • mybatis-plus 返回部分字段的解决方式

    Mybatis-Plus是Mybatis的增强工具,具有简化Mybatis使用的优点。本文将讲解如何在Mybatis-Plus中返回部分字段的解决方式。 方法一:使用wrapper Mybatis-Plus提供了Wrapper对象,可以通过select方法指定需要查询的字段。 例如,我们有一个User实体类,表示用户信息。假如我们只需要查询用户名和邮箱,可以…

    other 2023年6月25日
    00
  • mysql字符串索引优化方案

    MySQL字符串索引优化方案 在MySQL中,字符串类型字段一般都使用字符集来存储,例如UTF8、GBK、BIG5等。然而,针对这些字符串类型的查询操作,如果没有正确使用索引,会导致查询性能下降严重。本文将介绍MySQL中针对字符串类型字段的索引优化方案。 字符集选择 首先,我们需要选取与实际需求相符合的字符集,并且保证该字符集在MySQL中能够正确存储数据…

    其他 2023年3月29日
    00
  • go连接mysql的项目实践

    以下是Go连接MySQL的项目实践的完整攻略: 导入MySQL驱动程序 在Go项目中,我们需要导入MySQL驱动程序来连接和操作MySQL数据库。可以使用以下命令来安装MySQL驱动程序: go get -u github.com/go-sql-driver/mysql 连接到MySQL数据库 在Go代码中,我们可以使用database/sql包来连接和操作…

    other 2023年10月16日
    00
合作推广
合作推广
分享本页
返回顶部