FreeRTOS ~(六)信号量 ~ (1/3)信号量解决同步缺陷

news2024/11/18 6:29:29

前情提要
FreeRTOS ~(四)同步互斥与通信 ~ (1/3)同步的缺陷
FreeRTOS ~(五)队列的常规使用 ~ (1/5)队列解决同步缺陷
举例子说明:利用信号量解决前述的"同步的缺陷"问题

使用信号量的时候记得包含相关头文件,及打开相关宏定义
#include "semphr.h"
#define  configUSE_COUNTING_SEMAPHORES   1
这里使用的例子仍和开篇两个链接的一致
/*-----------------------------------------------------------*/
static int sum = 0;					/* i自增,结果存放变量sum */
static volatile int flagCalcEnd = 0;/* 该Flag用于监测代码运行时长 */
static SemaphoreHandle_t xSemCalc;	/* 创建的计数型信号量的句柄 */
/*-----------------------------------------------------------*/
void Task1Function(void * param)
{
	volatile int i = 0;
	while (1)
	{
		for (i = 0; i < 10000000; i++)
			sum++;
		/* 上述计算完成,就将计数型信号量增加1 */
		xSemaphoreGive(xSemCalc);
		/* 当前代码是删除Task1,
		   后面会讲到如果把这个删除了会怎么样?
		   如何保证sum这个数值不被破坏? */
		vTaskDelete(NULL);
	}
}

void Task2Function(void * param)
{
	while (1)
	{
		/* flag用逻辑分析仪查看代码执行时长 */
		flagCalcEnd = 0;
		/* 阻塞时间设置为最大,要一直等待直到Task1计算完成,
		   一旦能获取到信号量,就会退出阻塞态 */
		xSemaphoreTake(xSemCalc, portMAX_DELAY);
		flagCalcEnd = 1;
		printf("sum = %d\r\n", sum);
	}
}
/*-----------------------------------------------------------*/
int main( void )
{
	prvSetupHardware();
	
	/* 创建计数型信号量,最大计数值设置为10,初始计数值设置为0
	   在本例程设计中Task1完成复杂的计算后,就give一次,也就是
	   计数值会+1;只是验证信号量解决同步问题,这里设置为1也能
	   满足需求,暂且定为10次,后续可以让Task1 give多次 */
	xSemCalc = xSemaphoreCreateCounting(10, 0);
	
	xTaskCreate(Task1Function, "Task1", 100, NULL, 1, NULL);
	xTaskCreate(Task2Function, "Task2", 100, NULL, 1, NULL);
	
	vTaskStartScheduler();
	return 0;
}
Debug执行代码,用逻辑分析仪抓取flag变化,依此监测代码运行时长;
下图可以看到的是,代码只执行了3s就完成了计算,也就是在Task1进行计算的时候,Task2进入了阻塞态,没有参与调度,
因此3s可以认为是Task1独享CPU资源后,Task1完成计算的时间.
这就是我们想要的结果,解决了同步的缺陷.

在这里插入图片描述

上文中有提到,Task1执行完复杂的计算后就 vTaskDelete(NULL); 将自己删除掉了.
如果这里不删除掉会怎么样呢?
将上述代码中,仅修改这一个位置,修改如下:
void Task1Function(void * param)
{
	volatile int i = 0;
	while (1)
	{
		for (i = 0; i < 10000000; i++)
			sum++;
		xSemaphoreGive(xSemCalc);
		//vTaskDelete(NULL);
	}
}
运行观察会出现什么问题?
下图说明:Task1的计算完成了,并且将计数型信号量加1,但是打印的数据出现了问题;
也就是说没有计数型信号量做不到像队列那样可以将数据保存下来不被更改;
Task1计算完成for循环,give之后,此时如果Tick中断没有到呢?
那么Task1将继续执行for循环,sum将继续自增,因此我们要加上一些代码,实现想要的结果.

在这里插入图片描述

在上述代码的基础上,加入队列,以保证数据不被更改.
/*-----------------------------------------------------------*/
static int sum = 0;					/* i自增,结果存放变量sum */
static volatile int flagCalcEnd = 0;/* 该Flag用于监测代码运行时长 */
static SemaphoreHandle_t xSemCalc;	/* 创建的计数型信号量的句柄 */
static QueueHandle_t xQueueHandle1; /* 创建的队列的句柄 */
/*-----------------------------------------------------------*/
void Task1Function(void * param)
{
	volatile int i = 0;
	while (1)
	{
		for (i = 0; i < 10000000; i++)
			sum++;
		xSemaphoreGive(xSemCalc);
		/* 将计算完成的数据加入到队列中 */
		xQueueSend(xQueueHandle1,&sum,portMAX_DELAY);
		/* 这里同时将sum清零,验证上述的问题,这一步可做可不做 */
		sum = 0;
	}
}

void Task2Function(void * param)
{
    int val = 0;
	while (1)
	{
		flagCalcEnd = 0;
		xSemaphoreTake(xSemCalc, portMAX_DELAY);
		flagCalcEnd = 1;
		/* 队列接收数据,这里阻塞时间为0,因为代码能够执行到这里,
		   说明队列中一定是有数据的,因此无需等待 */
		xQueueReceive(xQueueHandle1,&val,0);
		printf("sum = %d\r\n", val);
	}
}
/*-----------------------------------------------------------*/
int main( void )
{
	prvSetupHardware();
	
	/* 创建队列 */
	xQueueHandle1 = xQueueCreate(2,sizeof(int));
	if( xQueueHandle1 == NULL )
	{
		printf("can not create queue 1\r\n");
	}
	/* 创建计数型信号量 */
	xSemCalc = xSemaphoreCreateCounting(10, 0);
	
	xTaskCreate(Task1Function, "Task1", 100, NULL, 1, NULL);
	xTaskCreate(Task2Function, "Task2", 100, NULL, 1, NULL);
	
	vTaskStartScheduler();
	return 0;
}
执行结果如下:

在这里插入图片描述

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

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

相关文章

最具价值开源项目收藏--持续更新

轻量级开源笔记应用&#xff08;memos&#xff09; 该项目基于 Go React.js SQLite 技术栈开发&#xff0c;兼具高性能与可定制性&#xff0c;适用于日常生活办公中的各类笔记管理场景。 开源地址&#xff1a;https://github.com/usememos/memos 跨平台无缝传输文件&#…

揭秘python函数:编程艺术的核心力量(3)

文章目录 前言递归lambda表达式lambda 的参数形式无参数位置参数关键字参数缺省参数可变参数1.包裹位置传递2.包裹关键字传递 带判断条件的lambda表达式列表数据按照字典key的值进行排序 高阶函数的使用内置高阶函数1.map()2.reduce()3.filter() 前言 前面我们已经学习了 pyth…

7-测试模型(2个)

目录 1.软件测试V模型 2.软件测试W模型&#xff08;双V模型&#xff09; 1.软件测试V模型 V模型最早是由Paul Rook在2&#xff10;世纪&#xff18;&#xff10;年代后期提出的&#xff0c;目的是改进软件开发的效率和效果。是瀑布模型的变种。 明确地标注了测试过程中存在的…

前端工程打包部署

打包 直接执行第二个脚本build即可 打包后的文件将会放在dist目录下 部署 NGINX&#xff1a;是一款轻量级的Web服务器/反向代理服务器及电子邮件&#xff08;IMAP/POP3&#xff09;代理服务器。其特点是占用内存少&#xff0c;并发能力强&#xff0c;在各大型互联网公司都有非…

R中高效安装包,以ComplexHeatmap包为例

包安装问题解决方案 1. Biocmanager安装 [2. 手动安装]&#xff08;正在更新……&#xff09; 目录 包安装问题解决方案前言1. install.packages()的介绍1.1 install.packages()的工作原理1.2 install.packages()安装失败的原因1.3 解决方案 2. BiocManage安装ComplexHeatmap总…

kubernetes的概念以及部署

简介&#xff1a; kubernetes&#xff0c;是一个全新的基于容器技术的分布式架构领先方案&#xff0c;是谷歌严格保密十几年的秘密武器----Borg系统的一个开源版本&#xff0c;于2014年9月发布第一个版本&#xff0c;2015年7月发布第一个正式版本。 kubernetes的本质是…

PDF怎么免费分割成多个文件?这几个方法非常好用!

记灵在线工具是一种常用的电子工具&#xff0c;尤其在工作和学习中&#xff0c;我们经常需要使用记灵工具进行文档处理和整理。其中&#xff0c;记灵工具的分割功能是非常有用的&#xff0c;因为它可以将一个大的文件分割成多个较小的文件&#xff0c;从而便于我们对文件进行分…

Ubuntu22.04如何安装steam游戏平台

linux终端安装 安装命令1 打开终端&#xff0c;输入以下命令安装&#xff1a; sudo snap install steam 安装命令2 1.在这种安装模式下&#xff0c;我们使用的是指令安装&#xff0c;这时我们需要打开终端&#xff08;cmd/控制台&#xff09;随后输入此指令&#xff1a;“su…

口语理解任务源码详解系列(三)利用BiRNN-attention模型实现

利用RNN-attention模型实现 写在前面 在前文介绍了项目的数据集构建&#xff1a;传送门&#xff0c;以及利用seq2seq-attention模型实现意图分类与槽位填充任务&#xff1a;传送门 本文利用BiRNN-attention实现&#xff1a;实现细节请参考论文&#xff1a;《Attention-Based Re…

一键搞定发布自己Jar到Maven中央仓库

做java 开发那当然离不开jar包管理, 不知何时一直想想封装一个自己的jar包 然后发布到maven中央仓库给别人使用。 hhh 我感觉自己写一个jar包工具然后&#xff0c;被很多人使用是一件很牛&#xff0c;很快乐事情。 终于有了这个机会&#xff0c;和时间。SpringBoot stater出来了…

Steam搬砖项目介绍

Steam搬砖项目&#xff1a;轻松赚取稳定收入的副业选择 对于许多数字游戏玩家来说&#xff0c;Steam平台并不陌生。今天&#xff0c;我将向您介绍一个稳定的副业选择——Steam搬砖项目。通通过简单的操作&#xff0c;您可以轻松获得几十上百元的利润。 介绍 Steam搬运砖项目…

css 伪元素和浮动

展示为行内元素 inline-block <style>div {/* 浏览器解析行内块或行内标签的时候, 如果标签换行书写会产生一个空格的距离, 展示为行内元素 */display: inline-block;width: 100px;height: 100px;}.one {background-color: pink;}.two {background-color: skyblue;}</…

基于OpenCV 实现车牌号码识别--附免费源码

在本教程中,您将学习如何使用 OpenCV 和 EasyOCR 包自动执行车牌/车牌识别 (LPR/NPR)。 EasyOCR是一个开源 Python 包,用于执行光学字符识别 - OCR(从图像中提取文本)。 该软件包非常易于使用,在撰写本文时,它支持 80 多种语言,包括中文、阿拉伯语、法语、英语、西里尔…

多元回归预测 | Matlab主成分分析PCA降维,BP神经网络回归预测。PCA-BP回归预测模型

文章目录 效果一览文章概述部分源码参考资料效果一览 文章概述 多元回归预测 | Matlab主成分分析PCA降维,BP神经网络回归预测。PCA-BP回归预测模型 评价指标包括:MAE、RMSE和R2等,代码质量极高,方便学习和替换数据。要求2018版本及以上。 部分源码 %% 清空环境变量 warnin…

【脚本语言】Shell Script - 日期的获取、设置和延时操作

目录 基础概念 基础语法 打印当前日期 打印纪元时 将日期转换为纪元时 打印要求格式的日期 设置日期和时间 基础概念 Bash可以帮助我们以不同的格式打印日期、设置日期&#xff0c;又或根据日期或时间进行操作等。 在类Unix系统中&#xff0c;日期被存储为一个整数&#xff0…

阿里云服务器架构x86、GPU、ARM、裸金属和超级计算集群说明

阿里云服务器架构有什么区别&#xff1f;X86计算、ARM计算、GPU/FPGA/ASIC、弹性裸金属服务器、超级计算集群有什么区别&#xff1f;阿里云服务器网分享云服务器ECS架构详细说明&#xff1a; 目录 阿里云服务器ECS架构说明 X86计算 ARM计算 GPU/FPGA/ASIC 弹性裸金属服务…

在 CI/CD流水线中运行自动化单元测试的4个原因

目录 什么是单元测试&#xff1f; C#中的单元测试示例 我需要在CI/CD 流水线中运行自动化测试吗&#xff1f; 开发人员代码验证反馈循环 预验证 步步为营 减少“另一个开发人员写了这段代码”的问题 什么是单元测试&#xff1f; 单元测试 什么是单元测试&#xff1f; 单…

【MySQL】内置函数详解

【MySQL】内置函数详解 日期函数字符串函数数学函数加密函数与其它 日期函数 --获取当前日期 mysql> select current_date(); ---------------- | current_date() | ---------------- | 2023-07-09 | ---------------- --获取当前时间 mysql> select current_time();…

ChatGLM2-6b本地部署

chatglm2-6m模型 git 地址 https://github.com/THUDM/ChatGLM2-6B 模型百度网盘地址&#xff1a;链接&#xff1a;https://pan.baidu.com/s/1-LFcPB0H23RSpTKOECsjxw?pwd5e3d 提取码&#xff1a;5e3d 1 模型简介 ChatGLM-6B 是一个开源的、支持中英双语的对话语言模型&#…

【高级程序设计语言C++】类与对象

2.1类的定义2.1.1 类的两种定义方式2.1.2 类的访问限定符2.1.3 C中的struct和class的区别是什么&#xff1f;2.1.4 类的实例化2.1.5 计算类对象的大小2.1.6 this指针 2.2 类的6个默认成员函数2.2.1 构造函数2.2.2 析构函数2.2.3 拷贝构造函数2.2.4 赋值运算符重载2.2.5 取地址及…