FreeRTOS信号量(二)

目录

1、计数型信号量简介

1、事件计数

2、资源管理

2、创建计数型信号量

​编辑1、函数xSemaphoreCreateCounting()

2、函数xSemaphoreCreateCountingStatic()

3 、计数型信号量创建过程分析

4、释放和获取计数信号量

信号量的释放

1 、函数 xSemaphoreGive()

2、函数xSemaphoreGiveFromISR()

获取信号量

1、函数 xSemaphoreTake()

2、函数xSemaphoreTakeFromISR ()

3.函数uxSemaphoreGetCount()

总结:


1、计数型信号量简介

        有些资料中也将计数型信号量叫做数值信号量,二值信号量相当于长度为 1 的队列,那么 计数型信号量就是长度大于 1 的队列。同二值信号量一样,用户不需要关心队列中存储了什么 数据,只需要关心队列是否为空即可。计数型信号量通常用于如下两个场合:

1、事件计数

2、资源管理

1、事件计数

在这个场合中,每次事件发生的时候就在事件处理函数中释放信号量(增加信号量的计数) ,其他任务会获取信号量( 信号量计数值减一,信号量值就是队列结构体成员变量 uxMessagesWaiting)来处理事件。在这种场合中创建的计数型信号量初始计数值为 0

2、资源管理

 在这个场合中,信号量值代表当前资源的可用数量,比如停车场当前剩余的停车位数量。 一个任务要想获得资源的使用权,首先必须获取信号量,信号量获取成功以后信号量值就会减 一。当信号量值为 0 的时候说明没有资源了。当一个任务使用完资源以后一定要释放信号量, 释放信号量以后信号量值会加一。在这个场合中创建的计数型信号量初始值应该是资源的数量, 比如停车场一共有 100 个停车位,那么创建信号量的时候信号量值就应该初始化为100

2、创建计数型信号量

FreeRTOS 提供了两个计数型信号量创建函数,如下表 :

1、函数xSemaphoreCreateCounting()

此函数用于创建一个计数型信号量,所需要的内存通过动态内存管理方法分配。此函数本质是一个宏,真正完成信号量创建的是函数 xQueueCreateCountingSemaphore(),此函数原型如 下:

SemaphoreHandle_t xSemaphoreCreateCounting(UBaseType_t      uxMaxCount,

                                                                                 UBaseType_t      uxInitialCount )

参数:

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

uxInitialCount: 计数信号量初始值。

返回值:

NULL:           计数型信号量创建失败。

其他值:          计数型信号量创建成功,返回计数型信号量句柄。

下面是在实际操作中使用的方法

2、函数xSemaphoreCreateCountingStatic()

此函数也是用来创建计数型信号量的,使用此函数创建计数型信号量的时候所需要的内存  需要由用户分配。此函数也是一个宏,真正执行的是函数xQueueCreateCountingSemaphoreStatic() 函数原型如下:

SemaphoreHandle_t xSemaphoreCreateCountingStatic( UBaseType_t      uxMaxCount,

                                                                              UBaseType_t                uxInitialCount,                                                                                     StaticSemaphore_t *  pxSemaphoreBuffer )

参数:

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

uxInitialCount: 计数信号量初始值。

pxSemaphoreBuffer指向一个 StaticSemaphore_t 类型的变量,用来保存信号量结构体。

返回值:

NULL:           计数型信号量创建失败。

其他值:          计数型号量创建成功,返回计数型信号量句柄。

3 、计数型信号量创建过程分析

这里只分析动态创建计数型信号量函数 xSemaphoreCreateCounting(),此函数是个宏,定义如下:

#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )

#define xSemaphoreCreateCounting( uxMaxCount, uxInitialCount )                          

xQueueCreateCountingSemaphore( ( uxMaxCount ), ( uxInitialCount ) )          

#endif

可以看出,真正干事的是函数 xQueueCreateCountingSemaphore(),此函数在文件 queue.c  有如下定义:

QueueHandle_txQueueCreateCountingSemaphore( const UBaseType_t  uxMaxCount,

                                                                                  const UBaseType_t    uxInitialCount )

QueueHandle_txHandle;

configASSERT( uxMaxCount != 0 );

configASSERT( uxInitialCount <= uxMaxCount );

xHandle = xQueueGenericCreate( uxMaxCount, \                    (1)                                                    queueSEMAPHORE_QUEUE_ITEM_LENGTH, \

                         queueQUEUE_TYPE_COUNTING_SEMAPHORE );

if( xHandle != NULL ) {

( ( Queue_t * ) xHandle )->uxMessagesWaiting = uxInitialCount;                                (2)

traceCREATE_COUNTING_SEMAPHORE(); }

else {

traceCREATE_COUNTING_SEMAPHORE_FAILED(); }

return xHandle;

}

(1)计数型信号量也是在队列的基础上实现的,所以需要调用函数xQueuGnenricCreate()创建应该队列,队列长度为uxMaxCount,对列项长度为queueSEMAPHORE_QUEUE_ITEM_LENGTH(此宏为0,队列的类型为queueQUEUE_TYPE_COUNTING_SEMAPHORE,表示是个计数型信号量。

(2)队列结构体的成员变量 uxMessagesWaiting 用于计数型信号量的计数,根据计数型信 号量的初始值来设置 uxMessagesWaiting。

4、释放和获取计数信号量

计数型信号量的释放和获取与二值信号量相同

信号量的释放

释放信号量的函数有两个,如下表:

       同队列一样,释放信号量也分为任务级和中断级。还有! 不管是二值信号量、计数型信号量还是互斥信号量,它们都使用上表中的函数释放信号量,递归互斥信号量有专用的释放函数。

1 、函数 xSemaphoreGive()

       此函数用于释放二值信号量、计数型信号量或互斥信号量,此函数是一个宏,真正释放信 号量的过程是由函数 xQueueGenericSend()来完成的,函数原型如下:

BaseType_t    xSemaphoreGive( xSemaphore )

参数:

xSemaphore要释放的信号量句柄。

返回值:

pdPASS:                         释放信号量成功。

errQUEUE_FULL:      释放信号量失败。

我们再来看一下函数 xSemaphoreGive()的具体内容,此函数在文件 semphr.h 中有如下定义:

#define xSemaphoreGive( xSemaphore )                                      

xQueueGenericSend( ( QueueHandle_t ) ( xSemaphore ),    

NULL,                                                                                    

semGIVE_BLOCK_TIME,                                                   

queueSEND_TO_BACK )

        可以看出任务级释放信号量就是向队列发送消息的过程,只是这里并没有发送具体的消息, 阻塞时间为 0(宏 semGIVE_BLOCK_TIME 为 0),入队方式采用的后向入队,入队的时候队列结构体成员变量 uxMessagesWaiting 会加一,对于二值信号量通过判断 uxMessagesWaiting 就可以知道信号量是否有效了,当 uxMessagesWaiting 为 1 的话说明二值信号量有效,为 0 就无效。如果队列满的话就返回错误值 errQUEUE_FULL,提示队列满,入队失败。

下面是相关计数型信号量的释放:

2、函数xSemaphoreGiveFromISR()

此函数用于在中断中释放信号量,此函数只能用来释放二值信号量和计数型信号量,绝对 不 能用来在中断服务函数中释放互斥信号量!此函数是一个宏,真正执行的是函数 xQueueGiveFromISR() ,此函数原型如下:

BaseType_t xSemaphoreGiveFromISR( SemaphoreHandle_t   xSemaphore,

                                                                BaseType_t *         pxHigherPriorityTaskWoken)

参数:

xSemaphore :   要释放的信号量句柄。

pxHigherPriorityTaskWoken :   标记退出此函数以后是否进行任务切换,这个变量的值由这

三个函数来设置的,用户不用进行设置,用户只需要提供一 个变量来保存这个值就行了。当此值为 pdTRUE 的时候在退 出中断服务函数之前一定要进行一次任务切换。

返回值:

pdPASS:                         释放信号量成功。

errQUEUE_FULL:      释放信号量失败。

         在中断中释放信号量真正使用的是函数 xQueueGiveFromISR(),此函数和中断级通用入队函数 xQueueGenericSendFromISR() 极其类似! 

只是针对信号量做了微 小 的 改 动 。 函 数 xSemaphoreGiveFromISR()不能用于在中断中释放互斥信号量,因为互斥信号量涉及到优先级继 承的问题,而中断不属于任务,没法处理中断优先级继承。大家可以参考第十三章分析函数 xQueueGenericSendFromISR()的过程来分析 xQueueGiveFromISR()。

获取信号量

获取信号量也有两个函数,如下表:

       同释放信号量的 API 函数一样,不管是二值信号量、计数型信号量还是互斥信号量,它们都使用表中的函数获取信号量

1、函数 xSemaphoreTake()

此函数用于获取二值信号量、计数型信号量或互斥信号量,此函数是一个宏,真正获取信 号量的过程是由函数 xQueueGenericReceive ()来完成的,函数原型如下:

BaseType_t xSemaphoreTake(SemaphoreHandle_t      xSemaphore,   

                                                 TickType_t                      xBlockTime)

参数:

xSemaphore要获取的信号量句柄。 xBlockTime:    阻塞时间。

返回值:

pdTRUE:       获取信号量成功。

pdFALSE:     超时,获取信号量失败。

再来看一下函数 xSemaphoreTake ()的具体内容,此函数在文件 semphr.h 中有如下定义:

 #define xSemaphoreTake( xSemaphore, xBlockTime )                 

xQueueGenericReceive( ( QueueHandle_t ) ( xSemaphore ),        

NULL,                                                  

( xBlockTime ),                                     

pdFALSE )

         取信号量的过程其实就是读取队列的过程,只是这里并不是为了读取队列中的消息。在讲解函数 xQueueGenericReceive()的时候说过如果队列为空并且阻塞时间为 0  的话就立即返回 errQUEUE_EMPTY,表示队列满。如果队列为空并且阻塞时间不为 0  的话就将任务 添加到延时列表中。如果队列不为空的话就从队列中读取数据(获取信号量不执行这一步),数 据读取完成以后还需要将队列结构体成员变量 uxMessagesWaiting  减一,然后解除某些因为入队而阻塞的任务,最后返回 pdPASS 表示出对成功。互斥信号量涉及到优先级继承,处理方式不同,后面讲解互斥信号量的时候在详细的讲解。

下面是该函数的操作案例:

2、函数xSemaphoreTakeFromISR ()

       此函数用于在中断服务函数中获取信号量,此函数用于获取二值信号量和计数型信号量, 绝对不能使用此函数来获取互斥信号量 ! 此函数是一个宏 , 真正执行的是函数 xQueueReceiveFromISR (),此函数原型如下:

BaseType_t xSemaphoreTakeFromISR(SemaphoreHandle_t   xSemaphore,

                                                                 BaseType_t *             pxHigherPriorityTaskWoken)

参数:

xSemaphore:   要获取的信号量句柄。

pxHigherPriorityTaskWoken :   标记退出此函数以后是否进行任务切换,这个变量的值由这

三个函数来设置的,用户不用进行设置,用户只需要提供一 个变量来保存这个值就行了。当此值为 pdTRUE 的时候在退 出中断服务函数之前一定要进行一次任务切换。

返回值:

pdPASS:                 获取信号量成功。

pdFALSE:             获取信号量失败。

       在中断中获取信号量真正使用的是函数 xQueueReceiveFromISR (),这个函数就是中断级出队函数!当队列不为空的时候就拷贝队列中的数据(用于信号量的时候不需要这一步),然后将队列结构体中的成员变量 uxMessagesWaiting 减一,如果有任务因为入队而阻塞的话就解除阻塞态,当解除阻塞的任务拥有更高优先级的话就将参数 pxHigherPriorityTaskWoken  设置为 pdTRUE,最后返回 pdPASS 表示出队成功。如果队列为空的话就直接返回 pdFAIL 表示出队失败!这个函数还是很简单的。

3.函数uxSemaphoreGetCount()

下面是用法:

该函数获取信号量 CountSemaphore 的信号量值,释放信号量的话信号量值就会加一。函数 uxSemaphoreGetCount()是用来获取信号量值的,这个函数是个宏,是对函数 uxQueueMessagesWaiting()的一个简单封装,其实就是返回队列结构体成员变量 uxMessagesWaiting 的值。

总结:

     计数型信号量是在FreeRTOS中常用到的信号量,不可或缺,必须要掌握,加以练习。

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

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

相关文章

加载指定会话最近消息

加载指定会话最近消息 前言 上一集我们就把三个标签页的加载列表的任务给完成啦&#xff01;那么我们这一集就来完成加载指定绘画最近消息的任务。 需求分析 我们点击了某个会话之后&#xff0c;我们就会去显示我们的会话的最近的N条消息。请看下图。 我们这里涉及到两个区…

SpringBoot3+SpringDataJPA+Ehcache3做分页查询的缓存优化

前言&#xff1a;关于集成Ehcache3的集成&#xff0c;需要了解的可以出门左转&#xff1a; https://blog.csdn.net/qq_42755868/article/details/143870473 这里 本文也是基于这个前置条件写的。大佬可以忽略哈。 基于上文&#xff1a;我们在做分页查询的时候&#xff0c;可以…

VS2022进行Libigl库编译

目录 一 编译OK 二 编译难点 2.1 cmake问题 2.2 文件编码问题 三 调用链接 一 编译OK 二 编译难点 2.1 cmake问题 vs2022直接多次cmake生成即可。 2.2 文件编码问题 格式保存为GB2312. 三 调用链接 https://github.com/libigl/libigl-example-project

风尚云网前端学习:一个简易前端新手友好的HTML5页面布局与样式设计

风尚云网前端学习&#xff1a;一个简易前端新手友好的HTML5页面布局与样式设计 简介 在前端开发的世界里&#xff0c;HTML5和CSS3是构建现代网页的基石。本文将通过一个简单的HTML5页面模板&#xff0c;展示如何使用HTML5的结构化元素和CSS3的样式特性&#xff0c;来创建一个…

返回流类型接口的错误信息处理

返回流类型接口的错误信息处理 前言axios拦截器src/utils/request.ts对应接口 前言 返回流类型接口需要在响应成功回调里拦截&#xff0c;且该接口的status始终是200&#xff0c;尽管后端返回的code可能是非2xx&#xff0c;因此返回流类型的接口&#xff0c;其错误信息需要单独…

SMMU软件指南操作之翻译过程概述

安全之安全(security)博客目录导读 下图展示了每个传入事务&#xff08;transaction&#xff09;所经过的简化过程。本节描述了顶层翻译过程。 一个传入事务遵循以下步骤&#xff1a; 1. 如果 SMMU 被全局禁用&#xff0c;事务将直接通过 SMMU 而不进行任何地址改变。全局属性…

特征交叉-MaskNet文章总结代码实现

MaskNet 这个模型是微博21年提出的&#xff0c;23年twitter(X)开源的推荐系统排序模块使用的backbone结构。 核心思想是认为DNN为主的特征交叉是addictive&#xff0c;交叉效率不高&#xff1b;所以设计了一种multiplicatvie的特征交叉 如何设计muliplicative特征交叉呢&#x…

QT 实现仿制 网络调试器(未实现连接唯一性) QT5.12.3环境 C++实现

网络调试助手&#xff1a; 提前准备&#xff1a;在编写代码前&#xff0c;要在.pro工程文件中&#xff0c;添加network模块。 服务端&#xff1a; 代码&#xff1a; widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QtWidgets> #inclu…

Vscode写markdown快速插入python代码

如图当我按下快捷键CRTLSHIFTK 自动出现python代码片段 配置方法shortcuts’ 打开这个json文件 输入 {"key": "ctrlshiftk","command": "editor.action.insertSnippet","when": "editorTextFocus","args&…

【案例】泛微.齐业成助力北京中远大昌汽车实现数电票全流程管理

中远大昌统一发票共享平台上线三个多月以来&#xff0c;实现&#xff1a; 5000份 60000元 发票开具 成本节约 客户简介及需求分析 北京中远大昌汽车服务有限公司&#xff08;以下简称“中远大昌”&#xff09;成立于2002年&#xff0c;是中远海运集团所属香远&#xff08;北…

使用docker快速部署Nginx、Redis、MySQL、Tomcat以及制作镜像

文章目录 应用快速部署NginxRedisMySQLTomcat 制作镜像镜像原理基于已有容器创建使用 Dockerfile 创建镜像指令说明构建应用创建 Dockerfile 文件创建镜像 应用快速部署 Nginx docker run -d -p 80:80 nginx使用浏览器访问虚拟机地址 Redis docker pull redis docker run --…

雅思阅读TFNG题型7大解题思路

雅思阅读TFNG题型7大解题思路&#xff0c;全在这了‼️ ⚠️在徘徊在6-6.5的同学有很大的共性就是对题型不够熟悉&#xff0c;我记得我当时卡6.5的时候我有时候分不清NG和F&#xff0c;有时候又分不清NG 和True&#xff0c;也不知道他有哪几种考我的方法&#xff0c;脑子里没有…

家政服务系统开发,智慧家政,便捷生活

近年来&#xff0c;大众对家政服务的需求不断增加&#xff0c;家政服务种类也逐渐多样化&#xff0c;涵盖了日常生活中的各个方面&#xff0c;为大众带来更急优质的服务&#xff0c;进一步提升了家政市场的发展。 在数字化发展的推动下&#xff0c;互联网家政服务的模式应运而…

重生之我在学环境变量

环境变量 基本概念 环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数如&#xff1a;我们在编写C/C代码的时候&#xff0c;在链接的时候&#xff0c;从来不知道我们的所链接的动态静态库在哪里&#xff0c;但 是照样可以链接成功&#…

Failed to start Docker Application Container Engine

说明&#xff1a; 1&#xff09;访问应用业务&#xff0c;读取不到数据&#xff0c;show databases;查看数据库报错 2&#xff09;重启docker服务&#xff0c;服务启动失败&#xff0c;查看日志报错如下图所示 3&#xff09;报错信息&#xff1a;chmod /data/docker: read-only…

SQL 语句执行计划中的连接方式

SQL 语句执行计划中的连接方式 join操作 join操作基本分为3大类&#xff1a;外连接&#xff08;细分为&#xff1a;左连接&#xff08;Left outer join/ left join&#xff09;、右连接&#xff08;right outer join/ right join&#xff09;、全连接&#xff08;full outer …

FileProvider高版本使用,跨进程传输文件

高版本的android对文件权限的管控抓的很严格,理论上两个应用之间的文件传递现在都应该是用FileProvider去实现,这篇博客来一起了解下它的实现原理。 首先我们要明确一点,FileProvider就是一个ContentProvider,所以需要在AndroidManifest.xml里面对它进行声明: <provideran…

golang 嵌入式armv7l压缩编译打包

编译 Go 应用程序 go build -ldflags"-s -w" -o myapp.exe . 使用 UPX 压缩可执行文件&#xff08;window下载并设置环境变量&#xff09; upx --best --lzma myapp.exe 可从10M压缩到1M 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 …

45.坑王驾到第九期:Mac安装typescript后tsc命令无效的问题

点赞收藏加关注&#xff0c;你也能主打别墅&#xff01; 一、问题描述 Mac上终端运行如下命令&#xff1a; sudo npm install typescript -g //全局安装ts提示成功安装后&#xff0c;我测试tsc -v这个命令时出现如下错误&#xff1a; 也就是说找不到 tsc 命令。 二、解决方…

【图像检测】深度学习与传统算法的区别(识别逻辑、学习能力、泛化能力)

识别逻辑 深度学习 使用了端到端的学习策略&#xff0c;直接学习从图像到检测结果的映射关系&#xff0c;自动提取特征&#xff0c;并且根据特征与特征之间的关系&#xff0c;计算出检测结果。 传统算法 则是人工提取特征&#xff0c;比如边缘特征&#xff0c;直线特征&#x…