二值信号量

news2024/11/25 3:42:45

Q: 什么是信号量?

A: 信号量(Semaphore),是在多任务环境下使用的一种机制,是可以用来保证两个或多个关键代码段不被并发调用。 信号量这个名字,我们可以把它拆分来看,“信号”可以起到通知信号的作用,“量”还可以用来表示资源的数量,当“量”只有0和1的时候,它就可以被称作“二值信号量”,只有两个状 ,当我们的那个量没有限制的时候,它就可以被称作为“计数型信号量”。 信号量也是队列的一种

Q: 什么是二值信号量?

A: 二值信号量其实就是一个长度为1,大小为零的队列,只有0和1两种状态,通常情况下,我们用 它来进行互斥访问或任务同步。

举例理解:

  • 互斥访问:比如门钥匙,只有获取到钥匙才可以开门
  • 任务同步:比如我写完一本书,别人才可以看这本书

二值信号量相关 API 函数

创建二值信号量

  •  返回值: 成功,返回对应二值信号量的句柄; 失败,返回 NULL 

释放二值信号量

  • xSemaphore:要释放的信号量句柄
  • 返回值: 成功,返回 pdPASS ; 失败,返回 errQUEUE_FULL 

获取二值信号量

  • xSemaphore:要获取的信号量句柄
  • xTicksToWait:超时时间(阻塞时间),0 表示不超时,portMAX_DELAY表示卡死等待;
  • 返回值: 成功,返回 pdPASS ; 失败,返回 errQUEUE_FULL 

实操演示

需求:创建一个二值信号量,按下 KEY1 则释放信号量,按下 KEY2 获取信号量。

在 C:\mjm_CubeMX_proj 路径下,复制一份Cube的母版并重命名为 :mjm_freeRTOS_Sema_Bi:

打开相应的Cube文件: 

1. 配置按钮的GPIO:

2. 找到左侧的Middleware --> FREERTOS,然后在下方找到"Task and Queues",然后创建两个任务:

3. 在“Timers and Semaphores” 中创建二值信号量:

4. 生成代码打开Keil:

4.1 在freertos.c中可以看到创建信号量和任务的代码:

注意,此处的osSemaphoreCreate()函数也是Cube对于创建二值信号量函数的封装:

但是有一个问题,上文中提到二值信号量的创建函数是“xSemaphoreCreateBinary()”,但是Cube中封装的对应函数确是“vSemaphoreCreateBinary()”,根据我关于FreeRTOS的函数命名规则的博客可知:本篇上文中提到“x”开头的函数返回的是任务句柄;而Cube中“v”开头的函数返回类型是void型也就是不返回。

我认为之所以Cube使用了“v”开头的函数是因为Cube把返回句柄的功能也封装起来了

可见上图函数返回的效果也是“成功创建返回句柄,失败返回NULL”

如果跳转这个“vSemaphoreCreateBinary()”:

如上图,和“xSemaphoreCreateBinary()”实现的效果也略有不同,这个“v”开头的函数不仅会创建一个二值信号量,并且如果创建成功,就会自动释放一个信号量

4.2 代码编写:

#include "stdio.h"

void StartTaskGive(void const * argument)
{
  for(;;)
  {
		if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET){
			osDelay(20);
			if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET){ //按键消抖
				printf("KEY1 has been pressed\r\n");
				if (xSemaphoreGive(myBinarySemHandle) == pdTRUE){ //释放信号量并判断返回值,如果返回成功
					printf("successfully give\r\n");
				}else{//如果返回失败
					printf("fail to give\r\n");
				}		
			}
			while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET); //等待按键松开,防止出现按钮一直按着,就一直删除创建任务			
		}
		osDelay(10);
  }
}


void StartTaskTake(void const * argument)
{
  for(;;)
  {
		if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1) == GPIO_PIN_RESET){
			osDelay(20);
			if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1) == GPIO_PIN_RESET){ //按键消抖
				printf("KEY2 has been pressed\r\n");
				if (xSemaphoreTake(myBinarySemHandle, 0 ) == pdTRUE){ //获取信号量并判断返回值,如果返回成功 
					printf("successfully take\r\n");
				}else{//如果返回失败
					printf("fail to take\r\n");
				}
			}
			while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1) == GPIO_PIN_RESET); //等待按键松开,防止出现按钮一直按着,就一直删除创建任务			
		}
		osDelay(10);
  }
}

实现效果

打开串口助手,先尝试按一下KEY1:

发现无法释放,原因就是刚刚提到的,Cube封装的函数在成功创建信号量之后就会直接释放,所以再次释放肯定会失败。

那如果现在按下KEY2:

 

和预想的一样,因为信号量已经被Cube的代码释放,所以可以成功获取

如果再按一下KEY2:

同时,获取信号量立刻fail的原因是我将获取信号量函数的“xTicksToWait”设置为了0,即只要没有就立刻返回,但是如果我设置为“portMAX_DELAY”此处就不会打印“fail to take”,而是会一直等待信号量的释放而卡死。

由于信号量在刚刚已经被获取,所以显然不能再获取一次

此时按下KEY1,再按下KEY2:

 

此时就可以成功释放一个信号量,并成功获取了

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

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

相关文章

CSDN原理等级的提升方法

文章目录 原力增长是一种积分型的社交平台,它有多个可以增长用户积分的渠道,也可以升级发付费资源,以下是几个主要的渠道:1.原创文章:2.回答问题:3.发动态:4.浏览文章:5.翻译文章&am…

回归预测 | MATLAB实现SO-CNN-BiLSTM蛇群算法优化卷积双向长短期记忆神经网络多输入单输出回归预测

回归预测 | MATLAB实现SO-CNN-BiLSTM蛇群算法优化卷积双向长短期记忆神经网络多输入单输出回归预测 目录 回归预测 | MATLAB实现SO-CNN-BiLSTM蛇群算法优化卷积双向长短期记忆神经网络多输入单输出回归预测预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 Matlab实…

8-Linux进程管理

Linux的进程管理 基本介绍显示系统执行的进程ps 指令基本介绍 终止进程kill和killall基本语法 查看进程树 pstree服务 service 管理service介绍service管理指令chkconfig 指令 systemctl 管理指令基本指令systemctl 设置服务的自启动状态示例打开或者关闭指定端口 动态监控进程…

[CrackMe]Brad Soblesky.1.exe和Brad Soblesky.2.exe的逆向及注册机编写

1. CrackMe小程序Brad Soblesky.1.exe分析 首先尝试程序功能, 发现其会弹出一个对话框, 上面有字符串, 可以通过直接定位MessageBox的位置, 但这里使用搜索字符串的方法: 查找所有字符串: 追踪到后, 就可以发现一个非常清晰的结构: 发现是明文, 立马就可以找到对应的密钥 2. Cr…

解决了项目中几个比较搞心态的bug(前端vue、小程序)

1、keep-alive 正常keep-alive的使用便可以做项目的缓存,但是我们的项目很不正常 项目是属于动态缓存,动态缓存有一个弊端 举个栗子: a组件为设置了需要缓存的页面; b组件为设置了需要缓存的页面; c组件为设置了不需…

nginx mirror代码分析

实现方式 mirror逻辑的工作阶段: ngx在log phase之后(在ngx_http_free_request处调用)已完成向client端返回response,在log phase之后完成close connection(短链接),在该阶段处理mirror逻辑不…

Gempy三维结构地质建模简明教程

Gempy 是一个开源 Python 库,用于生成完整的 3D 结构地质模型。 该库是一个完整的开发,用于从界面、断层和层方向创建地质模型,它还关联地质层的顺序以表示岩石侵入和断层顺序。 推荐:用 NSDT设计器 快速搭建可编程3D场景。 地质建…

【c++】vector的使用与模拟实现

🚀write in front🚀 📜所属专栏:初阶数据结构 🛰️博客主页:睿睿的博客主页 🛰️代码仓库:🎉VS2022_C语言仓库 🎡您的点赞、关注、收藏、评论,是对…

【Nodejs】操作mysql数据库

1.mysql 介绍 付费的商用数据库: Oracle,典型的高富帅;SQL Server,微软自家产品,Windows定制专款;DB2,IBM的产品,听起来挺高端;Sybase,曾经跟微软是好基友&a…

modbus tcp协议介绍及分析

一、modbus tcp协议介绍 Modbus TCP协议是基于TCP/IP网络的Modbus协议的一种变体。它将Modbus协议封装在TCP/IP协议栈中,使用以太网作为物理层,通过TCP连接来实现设备之间的通信。 Modbus TCP协议具有以下特点: 面向连接:Modbus T…

学习 C语言第二天 :C语言数据类型和变量(上)

目录: 1.数据类型介绍 2.signed和unsigned的介绍 3.数据类型的取值范围 1.数据类型介绍 C语言提供了丰富的数据类型来描述生活中的各种数据。使用整型类型来描述整数,使用字符类型来描述字符,使用浮点型类型来描述小数。所谓“类型”&#xf…

一文1500字从0到1搭建 Jenkins 自动化测试平台

Jenkins 自动化测试平台的作用 自动化构建平台的执行流程(目标)是: 我们将代码提交到代码托管工具上,如github、gitlab、gitee等。 1、Jenkins要能够检测到我们的提交。 2、Jenkins检测到提交后,要自动拉取代码&…

PostgreSQL构建时间

– PostgreSQL构建时间 select make_timestamp(2023,7,27,7,34,16);

python dataframe转置 多行转列

如上图 转置为下图: index_cols [身份证,手机号,serial_number]dfT df_last.set_index(index_cols).stack().unstack([0,1,2,])

EMP-SSL: TOWARDS SELF-SUPERVISED LEARNING IN ONETRAINING EPOCH

Recently, self-supervised learning (SSL) has achieved tremendous success in learning image representation. Despite the empirical success, most self-supervised learning methods are rather “inefficient” learners, typically taking hundreds of training epoch…

C++STL库中的vector

文章目录 vector的介绍及使用 vector深度剖析及模拟实现 动态二维数组理解 一、vector的介绍及使用 1.vector的介绍 1. vector是表示可变大小数组的序列容器。 2. 就像数组一样,vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素进…

进阶 vue3自定义指令 vue中常用自定义指令

文章目录 vue3自定义指令1.什么是自定义指令&#xff1f;2.注册自定义指令2.1 全局注册2.2 局部注册<script setup>中注册&#xff1a;<script>中使用&#xff1a; 3.钩子函数参数详解4.指令传值5.总结 常用自定义指令案例v-longpress 长按v-debounce 防抖v-thrott…

kubernetes安装问题记录

kubernetes安装问题记录 【1】未配置 host 文件警告1.1 原因1.2 解决方案 【2】swap 未禁用警告2.1 产生原因2.2 解决方式 【3】containerd 进程禁用了 cri 模块插件3.1 原因3.2 解决方法 问题1-3的完整错误日志【4】因错误中断再次 kubeadm init 报错4.1 原因4.2 解决方案 【5…

【学习篇】SAE J1939协议—常用到的知识点

前言&#xff1a;以下关于SAE J1939协议知识点的学习均抄录自书籍&#xff0c;侵权请联系删除。 故障诊断 SAE J1939诊断应用层定义了用于诊断服务的报文帧&#xff0c;诊断报文&#xff08;DM&#xff09;提供了用于车辆进行诊断和维修的功能。 诊断故障代码定义 SAE J193…

从Vue层面 - 解析发布订阅模式和观察者模式区别

目录 前言一、发布订阅模式什么是发布订阅模式&#xff1f;应用场景 二、观察者模式1&#xff09;什么是观察者模式&#xff1f;2&#xff09;应用场景3&#xff09;vue中的观察者模式观察者&#xff08;订阅者&#xff09; - Watcher目标者&#xff08;发布者&#xff09; - D…