【FreeRTOS】信号量——简介、常用API函数、注意事项、项目实现

在FreeRTOS中,信号量是一种非常重要的同步机制,用于实现任务间的互斥访问和同步操作。通过信号量,不同的任务可以安全地共享资源,避免竞争和冲突,从而确保系统的稳定性和可靠性。本篇博客将介绍FreeRTOS中信号量的基本概念、使用方法和实际应用,帮助读者深入理解信号量的原理和在实际项目中的应用场景。我们将从信号量的创建、获取和释放等方面进行详细讲解,并结合实际的示例代码,帮助读者更好地掌握FreeRTOS中信号量的使用技巧和注意事项。通过本篇博客的学习,读者将能够更加灵活地运用信号量来实现任务间的同步和资源共享,提高系统的可靠性和效率。


文章目录

    • 1.信号量简介
      • 1.1 二值信号量
      • 1.2 计数信号量
      • 1.3 互斥信号量
      • 1.4 递归信号量
      • 1.5 信号量控制块
    • 2.常用信号量API函数
      • 2.1 创建信号量函数
        • 2.1.1 创建二值信号量 xSemaphoreCreateBinary()
        • 2.1.2 创建计数信号量 xSemaphoreCreateCounting()
      • 2.2 信号量删除函数 vSemaphoreDelete()
      • 2.3 信号量释放函数
        • 2.3.1 xSemaphoreGive()
        • 2.3.2 xSemaphoreGiveFromISR()
      • 2.4 信号量获取函数
        • 2.4.1 xSemaphoreTake()
        • 2.4.2 xSemaphoreTakeFromISR()
    • 3.例子说明


1.信号量简介

信号量Semaphore)是一种实现任务间通信的机制,可以实现任务之间同步或临界资源的互斥访问,常用于协助一组相互竞争的任务来访问临界资源。在多任务系统中,各任务之间需要同步或互斥实现临界资源的保护,信号量功能可以为用户提供这方面的支持。

1.1 二值信号量

二值信号量既可以用于临界资源访问也可以用于同步功能。

在这里插入图片描述

只能取两个值:01。这种信号量通常用于实现互斥访问,即只有一个进程或线程可以访问共享资源。当一个进程或线程占用资源时,二值信号量的值为1,其他进程或线程需要等待,直到信号量的值变为0才能访问资源。

二值信号量通常用于解决临界区问题,即多个进程或线程需要访问共享资源时可能会导致数据不一致或竞争条件的问题。通过使用二值信号量,可以有效地控制对共享资源的访问,避免出现这些问题。

在实际应用中,二值信号量通常与互斥锁mutex)结合使用,以实现对共享资源的互斥访问。当一个进程或线程需要访问共享资源时,首先尝试对二值信号量进行加操作,如果成功则可以访问资源,否则需要等待。在访问完成后,再对二值信号量进行减操作,释放资源。


1.2 计数信号量

二进制信号量可以被认为是长度为 1 的队列,而计数信号量则可以被认为长度大于 1的队列,信号量使用者依然不必关心存储在队列中的消息,只需关心队列是否有消息即可。

在这里插入图片描述

一种可以取多个值的信号量,它用于控制对一组资源的访问数量。计数信号量的值可以大于等于0,表示可用的资源数量。当一个进程或线程需要访问资源时,它会尝试对计数信号量进行减操作,如果计数信号量的值大于0,则可以访问资源,同时计数信号量的值会减少;如果计数信号量的值为0,则需要等待,直到有其他进程或线程释放资源,使计数信号量的值大于0。

计数信号量通常用于实现对一组资源的并发访问控制,例如限制同时访问某个资源的进程或线程的数量。这种机制可以有效地控制资源的并发访问,避免资源被过度占用,提高系统的性能和稳定性。

在实际应用中,计数信号量可以用于实现线程池、连接池等并发控制的场景,以及限制对其他有限资源的并发访问。通过合理地管理计数信号量的值,可以有效地控制对资源的并发访问,避免出现竞争条件和数据不一致的问题。


1.3 互斥信号量

互斥信号量其实是特殊的二值信号量,由于其特有的优先级继承机制从而使它更适用于简单互锁,也就是保护临界资源。

在这里插入图片描述

只能取两个值:0和1。它用于实现对共享资源的互斥访问,即只有一个进程或线程可以访问共享资源。当一个进程或线程占用资源时,互斥信号量的值为1,其他进程或线程需要等待,直到信号量的值变为0才能访问资源。

互斥信号量通常与互斥锁(mutex)等同步机制结合使用,以实现对共享资源的互斥访问。在访问共享资源之前,进程或线程会尝试对互斥信号量进行减操作,如果成功则可以访问资源,否则需要等待。在访问完成后,再对互斥信号量进行加操作,释放资源。

互斥信号量是实现进程同步和互斥的重要工具,它能够有效地避免竞争条件和数据不一致的问题。在并发编程中,互斥信号量通常用于保护临界区,即一段代码在同一时间只能被一个线程执行,以确保数据的一致性和正确性。


1.4 递归信号量

允许同一线程多次对信号量进行加操作,而不会导致死锁。通常情况下,普通的信号量在同一线程内多次对信号量进行加操作可能会导致死锁,因为信号量的值会被多次减少,但只有一次加操作来释放资源。

递归信号量则允许同一线程多次对信号量进行加操作,每次加操作都会增加信号量的值,从而避免了死锁的情况。这种机制通常用于需要在递归函数中对共享资源进行加锁的情况,以及其他需要在同一线程内多次对资源进行加锁的情况。


1.5 信号量控制块

在这里插入图片描述
在这里插入图片描述


2.常用信号量API函数

2.1 创建信号量函数

2.1.1 创建二值信号量 xSemaphoreCreateBinary()
  • 原型:SemaphoreHandle_t xSemaphoreCreateBinary( void );
  • 作用:用于创建一个二值信号量,用于实现对共享资源的互斥访问。
  • 参数:无参数。
  • 返回值:返回一个 SemaphoreHandle_t 类型的句柄,表示创建的二值信号量。

xSemaphoreCreateBinary() 函数的作用是创建一个二值信号量,二值信号量的初始值为0,用于实现对共享资源的互斥访问。它返回一个 SemaphoreHandle_t 类型的句柄,可以用于后续对该二值信号量进行操作。


2.1.2 创建计数信号量 xSemaphoreCreateCounting()
  • 原型:SemaphoreHandle_t xSemaphoreCreateCounting( UBaseType_t uxMaxCount, UBaseType_t uxInitialCount );
  • 作用:用于创建一个计数信号量,用于控制对一组资源的并发访问数量。
  • 参数:
    • uxMaxCount:计数信号量的最大计数值。
    • uxInitialCount:计数信号量的初始计数值。
  • 返回值:返回一个 SemaphoreHandle_t 类型的句柄,表示创建的计数信号量。

xSemaphoreCreateCounting() 函数用于创建一个计数信号量,计数信号量的初始值为 uxInitialCount,最大计数值为 uxMaxCount。计数信号量通常用于限制对一组资源的并发访问数量,通过合理地管理计数信号量的值,可以有效地控制对资源的并发访问,避免出现竞争条件和数据不一致的问题。


2.2 信号量删除函数 vSemaphoreDelete()

  • 原型:void vSemaphoreDelete( SemaphoreHandle_t xSemaphore );
  • 作用:用于删除一个已经创建的信号量。
  • 参数:
    • xSemaphore:要删除的信号量的句柄。
  • 返回值:无。

vSemaphoreDelete() 函数用于删除一个已经创建的信号量,通过传入要删除的信号量的句柄 xSemaphore 来实现。一旦删除了信号量,其句柄将不再有效,并且不能再对该信号量进行操作。


2.3 信号量释放函数

2.3.1 xSemaphoreGive()
  • 原型:BaseType_t xSemaphoreGive( SemaphoreHandle_t xSemaphore );
  • 作用:用于释放一个二值信号量或增加一个计数信号量的计数值。
  • 参数:
    • xSemaphore:要释放的信号量的句柄。
  • 返回值:如果释放成功,则返回 pdTRUE,否则返回 pdFALSE。

xSemaphoreGive() 函数用于释放一个二值信号量或增加一个计数信号量的计数值。对于二值信号量,调用该函数会将信号量的计数值从 0 增加到 1;对于计数信号量,调用该函数会增加信号量的计数值。如果有任务因等待该信号量而被唤醒,则调用 xSemaphoreGive() 会使其中一个等待的任务得以继续执行。


2.3.2 xSemaphoreGiveFromISR()
  • 原型:BaseType_t xSemaphoreGiveFromISR( SemaphoreHandle_t xSemaphore, BaseType_t *pxHigherPriorityTaskWoken );
  • 作用:用于从中断服务程序中释放一个二值信号量或增加一个计数信号量的计数值。
  • 参数:
    • xSemaphore:要释放的信号量的句柄。
    • pxHigherPriorityTaskWoken:一个指向 BaseType_t 类型的指针,用于指示是否有一个高优先级任务被唤醒。
  • 返回值:如果释放成功,则返回 pdTRUE,否则返回 pdFALSE。

xSemaphoreGiveFromISR() 函数与 xSemaphoreGive() 函数类似,用于从中断服务程序中释放信号量。它可以用于在中断服务程序中释放信号量,以唤醒等待该信号量的任务。与 xSemaphoreGive() 不同的是,xSemaphoreGiveFromISR() 可以唤醒一个等待该信号量的高优先级任务,并通过 pxHigherPriorityTaskWoken 参数指示是否有高优先级任务被唤醒。


2.4 信号量获取函数

2.4.1 xSemaphoreTake()
  • 原型:BaseType_t xSemaphoreTake( SemaphoreHandle_t xSemaphore, TickType_t xTicksToWait );
  • 作用:用于获取一个二值信号量或减少一个计数信号量的计数值。
  • 参数:
    • xSemaphore:要获取的信号量的句柄。
    • xTicksToWait:等待获取信号量的最长时间,以时钟节拍数(tick)表示。
  • 返回值:如果成功获取信号量,则返回 pdTRUE,否则返回 pdFALSE。

xSemaphoreTake() 函数用于获取一个二值信号量或减少一个计数信号量的计数值。如果信号量的计数值大于 0,则获取成功,计数值减一;如果信号量的计数值为 0,则任务将进入阻塞状态,直到信号量可用或超时。

xTicksToWait 参数用于指定任务在获取信号量时的最长等待时间。如果设置为 portMAX_DELAY,任务将一直等待直到信号量可用;如果设置为 0,则任务将立即返回获取结果而不进行等待;如果设置为其他数值,则任务将等待指定的时钟节拍数后返回获取结果。


2.4.2 xSemaphoreTakeFromISR()
  • 原型:BaseType_t xSemaphoreTakeFromISR( SemaphoreHandle_t xSemaphore, BaseType_t *pxHigherPriorityTaskWoken );
  • 作用:用于从中断服务程序中获取一个二值信号量或减少一个计数信号量的计数值。
  • 参数:
    • xSemaphore:要获取的信号量的句柄。
    • pxHigherPriorityTaskWoken:一个指向 BaseType_t 类型的指针,用于指示是否有一个高优先级任务被唤醒。
  • 返回值:如果成功获取信号量,则返回 pdTRUE,否则返回 pdFALSE。

xSemaphoreTakeFromISR() 函数与 xSemaphoreTake() 函数类似,用于从中断服务程序中获取信号量。它可以用于在中断服务程序中获取信号量,以等待信号量可用或减少信号量的计数值。与 xSemaphoreTake() 不同的是,xSemaphoreTakeFromISR() 可以唤醒一个等待该信号量的高优先级任务,并通过 pxHigherPriorityTaskWoken 参数指示是否有高优先级任务被唤醒。


3.例子说明

当在STM32上使用FreeRTOS时,可以使用信号量来实现任务间的同步和互斥访问。以下是一个简单的示例,演示了如何在STM32上使用FreeRTOS中的信号量。

假设我们有两个任务:Task1 和 Task2,它们需要共享一个资源,我们可以使用信号量来进行同步。Task1 将获取资源并执行一些操作,然后释放资源;Task2 将等待资源可用,然后获取资源并执行操作。

#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"// 定义一个全局的信号量句柄
SemaphoreHandle_t xSemaphore;void Task1(void *pvParameters) {while (1) {// 尝试获取信号量,等待最长100个时钟节拍if (xSemaphoreTake(xSemaphore, 100) == pdTRUE) {// 信号量获取成功,执行任务1的操作// ...// 释放信号量xSemaphoreGive(xSemaphore);} else {// 等待超时或者获取失败的处理// ...}}
}void Task2(void *pvParameters) {while (1) {// 尝试获取信号量,等待最长100个时钟节拍if (xSemaphoreTake(xSemaphore, 100) == pdTRUE) {// 信号量获取成功,执行任务2的操作// ...// 释放信号量xSemaphoreGive(xSemaphore);} else {// 等待超时或者获取失败的处理// ...}}
}int main(void) {// 创建一个二值信号量xSemaphore = xSemaphoreCreateBinary();// 创建任务 Task1xTaskCreate(Task1, "Task1", configMINIMAL_STACK_SIZE, NULL, 1, NULL);// 创建任务 Task2xTaskCreate(Task2, "Task2", configMINIMAL_STACK_SIZE, NULL, 2, NULL);// 启动调度器vTaskStartScheduler();while (1) {// 如果调度器启动失败,进行错误处理// ...}
}

在上面的示例中,我们首先创建了一个二值信号量 xSemaphore,然后在 Task1Task2 中使用 xSemaphoreTake()xSemaphoreGive() 来获取和释放信号量。

在每个任务中,我们使用 xSemaphoreTake() 函数来尝试获取信号量。如果获取成功,任务就可以执行相应的操作;如果获取失败,任务将等待一段时间(这里是100个时钟节拍)然后再次尝试获取。获取成功后,任务执行完操作后使用 xSemaphoreGive() 来释放信号量。

这样,通过信号量的获取和释放,我们可以实现 Task1 和 Task2 之间的资源共享和同步。这样的设计可以确保两个任务之间的操作不会相互干扰,从而实现了任务间的同步和互斥访问。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/207350.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用Huggingface创建大语言模型RLHF训练流程的完整教程

ChatGPT已经成为家喻户晓的名字,而大语言模型在ChatGPT刺激下也得到了快速发展,这使得我们可以基于这些技术来改进我们的业务。 但是大语言模型像所有机器/深度学习模型一样,从数据中学习。因此也会有garbage in garbage out的规则。也就是说…

AUTOSAR CP Int-Watchdog简介

Int Watchdog 1 简介2 EB 中配置 TC39X3 Wdg 在代码中使用1 简介 内部看门狗驱动[sws_Wdg_00161]要访问内部看门狗硬件,对应的 Wdg 模块实例应该直接访问看门狗服务的硬件。提示:内部看门狗驱动程序是微控制器抽象层的一部分,它允许直接的硬件访问。注意:内部看门狗的日常服…

第21章总结 网络通信

21.1 网络程序设计基础 网络程序设计编写的是与其他计算机进行通信的程序。Java已经将网络程序所需要的元素封装成不同的类,用户只要创建这些类的对象,使用相应的方法,即使不具备有关的网络知识,也可以编写出高质量的网络通信程序…

【评测脚本】机器信息评测(初版)

背景 QA的实际工作过程中,除了业务相关的测试外,也会涉及到一些评测相关的工作,甚至还要做多版本、多维度的评估分析。尤其是现在火热的大模型,相关的评测内容更是核心中的核心。当然本文的内容只是做一些初级的机器相关的评测信息,更多更广的评测需要更多时间的积累和总…

JVM的内存结构详解「重点篇」

一、JVM虚拟机数据区 虚拟机栈 1、 线程私有 2、 每个方法被执行的时候都会创建一个栈帧用于存储局部变量表,操作栈,动态链接,方法出口等信息。每一个方法被调用的过程就对应一个栈帧在虚拟机栈中从入栈到出栈的过程。 3、栈帧: 是用来存储…

安装mysql数据库

1.1下载APT存储库(下载链接) 1.2安装APT存储库(注意好正确的路径) 将下载的文件传输到linux服务器对应目录下后执行以下命令: sudo dpkg -i mysql-apt-config_0.8.10-1_all.deb 选择mysql5.7 然后点击ok 然后执行 s…

应用架构——集群、分布式、微服务的概念及异同

一、什么是集群? 集群是指将多台服务器集中在一起, 每台服务器都实现相同的业务,做相同的事;但是每台服务器并不是缺 一不可,存在的主要作用是缓解并发能力和单点故障转移问题。 集群主要具有以下特征: …

JAVA使用POI向doc加入图片

JAVA使用POI向doc加入图片 前言 刚来一个需求需要导出一个word文档,文档内是系统某个界面的各种数据图表,以图片的方式插入后导出。一番查阅资料于是乎着手开始编写简化demo,有关参考poi的文档查阅 Apache POI Word(docx) 入门示例教程 网上大多数是XXX…

el-table-column 添加 class类

正常添加class 发现没有效果 class"customClass" 发现并没有添加上去 看了一下官网发现 class-name 可以实现 第一步: :class-name"customClass" 第二步 : customClass: custom-column-class, 然后就发现可以了

Qt简介、工程文件分离、创建Qt工程、Qt的帮助文档

QT 简介 core:核心模块,非图形的接口类,为其它模块提供支持 gui:图形用户接口,qt5之前 widgets:图形界面相关的类模块 qt5之后的 database:数据库模块 network:网络模块 QT 特性 开…

IntelliJ IDEA使用Eval Reset

文章目录 IntelliJ IDEA使用Eval Reset说明具体操作 IntelliJ IDEA使用Eval Reset 说明 操作系统:windows10 版本:2020.1 IntelliJ IDEA安装可查看:安装教程 具体操作 添加,输入网址 https://plugins.zhile.io然后搜索“IDE E…

IntelliJ IDEA安装

文章目录 IntelliJ IDEA安装说明下载执行安装 IntelliJ IDEA安装 说明 操作系统:windows10 版本:2020.1 下载 官网地址 执行安装

奇点云2023数智科技大会来了,“双12”直播见!

企业数字化进程深入的同时,也在越来越多的新问题中“越陷越深”: 数据暴涨,作业量和分析维度不同以往,即便加了机器,仍然一查就崩; 终于搞定新增渠道数据的OneID融合,又出现几个渠道要变更&…

自动定量包装机市场研究: 2023年行业发展潜力分析

中国包装机械业取得了快速发展,但也出现了一些低水平重复建设现象。据有关资料显示,与工业发达国家相比,中国食品和包装机械产品品种缺乏25%-30%,技术水平落后15-25年。我国包装专用设备制造行业规模以上企业有319家,主…

Vue3实现一个拾色器功能

​ <template><div class"color"><button v-if"hasEyeDrop" click"nativePick">点击取色</button><input v-else type"color" input"nativePick" v-model"selectedColor" /><p&…

Markdown从入门到精通

Markdown从入门到精通 文章目录 Markdown从入门到精通前言一、Markdown是什么二、Markdown优点三、Markdown的基本语法3.1 标题3.2 字体3.3 换行3.4 引用3.5 链接3.6 图片3.7 列表3.8 分割线3.9 删除线3.10 下划线3.11 代码块3.12 表格3.13 脚注3.14 特殊符号 四、Markdown的高…

2024黑龙江省职业院校技能大赛信息安全管理与评估样题第二三阶段

2024黑龙江省职业院校技能大赛暨国赛选拔赛 "信息安全管理与评估"样题 *第二阶段竞赛项目试题* 本文件为信息安全管理与评估项目竞赛-第二阶段试题&#xff0c;第二阶段内容包括&#xff1a;网络安全事件响应、数字取证调查和应用程序安全。 极安云科专注技能竞赛…

openharmony 开发环境搭建和系统应用编译傻瓜教程

一、DevEco Studio 安装 当前下载版本有两个&#xff0c;由于低版本配置会有各种问题&#xff0c;我选择高版本安装 低版本下载链接 HUAWEI DevEco Studio和SDK下载和升级 | HarmonyOS开发者 高版本下载链接 OpenAtom OpenHarmony 解压后安装 双击安装 安装配置 二、创建测…

IntelliJ IDEA的下载安装配置步骤详解

引言 IntelliJ IDEA 是一款功能强大的集成开发环境&#xff0c;它具有许多优势&#xff0c;适用于各种开发过程。本文将介绍 IDEA 的主要优势&#xff0c;并提供详细的安装配置步骤。 介绍 IntelliJ IDEA&#xff08;以下简称 IDEA&#xff09;之所以被广泛使用&#xff0c;…

docker镜像仓库hub.docker.com无法访问

docker镜像仓库hub.docker.com无法访问 文章主要内容&#xff1a; 介绍dockerhub为什么无法访问解决办法 1 介绍dockerhub为什么无法访问 最近许多群友都询问为什么无法访问Docker镜像仓库&#xff0c;于是我也尝试去访问&#xff0c;结果果然无法访问。 大家的第一反应就是…