FreeRTOS 队列传递结构体、内存块等复合数据类型

news2024/10/1 7:46:59

1. 队列一般传递的不是单个整型数据或者字符型数据,而是传递结构体或者内存块,一块内存的指针

在这里插入图片描述

2. 定义结构体数据类型

/* 定义队列传递的结构类型。 */ 
typedef struct { 
	unsigned char ucValue; 
	unsigned char ucSource; 
} xData; 

/* 声明两个xData类型的变量,通过队列进行传递。 */ 
static const xData xStructsToSend[ 2 ] = { 
	{ 100, mainSENDER_1 }, // task1 传递的结构体参数
	{ 200, mainSENDER_2 } // task2 传递的结构体参数
};

3. 往队列里面写入结构体参数

static void vSenderTask(void *pvParameters) 
{ 
	xData lValueToSend; 
	portBASE_TYPE xStatus;
	
	lValueToSend = (xData)pvParameters;  // 两个任务都使用这个函数vSenderTask,并在此接收各自的实参
	
	for(;;) 
	{ 
		/* 往队列发送数据
		   第一个参数是要写入的队列
		   第二个参数是被发送数据的地址
           第三个参数是阻塞超时时间: 当队列满时,任务转入阻塞状态以等待队列空间有效。本例中没有设定超时时间,因为此队列决不会保持有超过一个数据单元的机会,所以也决不会满。
	     */ 
		xStatus = xQueueSendToBack(xQueue, &lValueToSend, 0); 
		if (xStatus != pdPASS) 
		{ 
			/* 发送操作由于队列满而无法完成 – 这必然存在错误,因为本例中的队列不可能满。 */ 
			printf("Could not send to the queue.\r\n"); 
		} 
		/* 允许其它发送任务执行。 taskYIELD()通知调度器现在就切换到其它任务,而不必等到本任务的时间片耗尽 */ 
		taskYIELD(); 
	} 
}

4. 从队列中读出结构体

static void vReceiverTask( void *pvParameters ) 
{ 
	/* 声明结构体变量以保存从队列中读出的数据单元 */ 
	xData xReceivedStructure; 
	portBASE_TYPE xStatus; 
	/* This task is also defined within an infinite loop. */ 
	for( ;; ) 
	{ 
		/* 读队列任务的优先级最低,所以其只可能在写队列任务阻塞时得到执行。而写队列任务只会在队列写满时才会进入阻塞态,所以
	   	   读队列任务执行时队列肯定已满。所以队列中数据单元的个数应当等于队列的深度 – 本例中队列深度为3 */ 
		if( uxQueueMessagesWaiting( xQueue ) != 3 ) 
		{ 
			printf( "Queue should have been full!\r\n" ); 
		} 
		/* Receive from the queue. 
		第二个参数是存放接收数据的缓存空间。本例简单地采用一个具有足够空间大小的变量的地址。
		第三个参数是阻塞超时时间 – 本例不需要指定超时时间,因为读队列任会只会在队列满时才会得到执行,故而不会因队列空而阻塞 */ 
		xStatus = xQueueReceive( xQueue, &xReceivedStructure, 0 ); 
		if( xStatus == pdPASS ) 
		{ 
			/* 数据成功读出,打印输出数值及数据来源。 */ 
			if( xReceivedStructure.ucSource == mainSENDER_1 ) 
			{ 
				printf( "From Sender 1 = %d\r\n", xReceivedStructure.ucValue ); 
			} 
			else 
			{ 
				printf( "From Sender 2 = %d\r\n", xReceivedStructure.ucValue ); 
			} 
		} 
		else 
		{ 
			/* 没有读到任何数据。这一定是发生了错误,因为此任务只支在队列满时才会得到执行 */ 
			printf( "Could not receive from the queue.\r\n" ); 
		} 
	} 
}

5. main 函数中创建队列 & 写任务1 & 写任务2 & 读任务

写任务优先级比读任务优先级高,所以会先一直写,知道队列里面写满了数据,写任务阻塞,然后才开始读,读走一个数据,读任务立马被写任务抢占,又写一个数据进去,循环写,读

int main( void ) 
{ 
	/* 创建队列用于保存最多3个xData类型的数据单元。 */ 
	xQueue = xQueueCreate( 3, sizeof( xData ) ); 
	if( xQueue != NULL ) 
	{ 
		/* 为写队列任务创建2个实例。 任务入口参数用于传递发送到队列中的数据。因此其中一个任务往队列中一直写入xStructsToSend[0],而另一个则往队
		   列中一直写入xStructsToSend[1]。这两个任务的优先级都设为2,高于读队列任务的优先级 */ 
		xTaskCreate( vSenderTask, "Sender1", 1000, &(xStructsToSend[0]), 2, NULL ); 
		xTaskCreate( vSenderTask, "Sender2", 1000, &(xStructsToSend[1]), 2, NULL ); 
		/* 创建读队列任务。读队列任务优先级设为1,低于写队列任务的优先级。 */ 
		xTaskCreate( vReceiverTask, "Receiver", 1000, NULL, 1, NULL ); 
		
		vTaskStartScheduler(); 
	} 
	else 
	{ 
		/* 创建队列失败。 */ 
	} 
	/* 如果一切正常,main()函数不应该会执行到这里。但如果执行到这里,很可能是内存堆空间不足导致空闲任务无法创建。第五章将提供更多关于内存管理方面的信息 */ 
	for( ;; )
	{
	} 
}

6. 输出结果

在这里插入图片描述

7. 任务的执行流程,切换过程

优先级高的会抢占优先级低的,老二在睡觉,老大一脚踢走,老大要睡觉了
优先级一样的,等待时间最久的优先执行
在这里插入图片描述

8. 用队列来传递大型数据的时候,最好使用指针,指向一块内存的指针,把指针传来传去就可以了,然后再通过指针来操作里面的任一数据,常用的做法,速度,效率,节省内存,还方便

8.1 指针指向的内存空间的所有权必须明确

当任务间通过指针共享内存时,应该从根本上保证所不会有任意两个任务同时修改共享内存中的数据,或是以其它行为方式使得共享内存数据无效或产生一致性问题。原则上,共享内存在其指针发送到队列之前,其内容只允许被发送任务访问;共享内存指针从队列中被读出之后,其内容亦只允许被接收任务访问

8.2 指针指向的内存空间必须有效

如果指针指向的内存空间是动态分配的,只应该有一个任务负责对其进行内存释放。当这段内存空间被释放之后,就不应该有任何一个任务再访问这段空间。
切忌用指针访问任务栈上分配的空间。因为当栈帧发生改变后,栈上的数据将不再有效。

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

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

相关文章

使用@RequiredArgsConstructor注入时@Qualifier失效问题

在一个项目中,使用到了 Lombok 的RequiredArgsConstructor注解来注入对象 Service RequiredArgsConstructor public class DeliveryServiceImpl implements DeliveryService {private final ResourceDao resourceDao; }因为ResourceDao接口有两个实现类 Repositor…

5大趋势!牛客CEO叶向宇深度解读《2023春季校园招聘白皮书》

校招并不只是一场求职者与企业间的相互选择,而是一场关乎未来的人才战略布局。 近日,牛客CEO叶向宇在「数智链接 向新而生」牛客青年人才招聘峰会中深度解读了《牛客2023春季校园招聘白皮书》中的5大校招趋势,为我们提供了宝贵的洞察。 01.校…

公司刚上市就来了个从字节拿28K的人,让我见识到了什么才是测试天花板···

5年测试,应该是能达到资深测试的水准,即不仅能熟练地开发业务,而且还能熟悉项目开发,测试,调试和发布的流程,而且还应该能全面掌握数据库等方面的技能,如果技能再高些的话,甚至熟悉分…

对作用域链的理解

一、作用域 作用域,即变量(变量作用域又称上下文)和函数生效(能被访问)的区域或集合 换句话说,作用域决定了代码区块中变量和其他资源的可见性 举个例子 function myFunction() {let inVariable "…

厉害的人都在用的思维导图-思维导图的七大图示

思维导图是一种非常实用的工具,它可以帮助我们更好地组织和表达自己的思想。 在这篇文章中,我将会介绍用ProcessOn完成思维导图的7大图示,并解释它们各自的作用和应用场景。 思维导图是一种非常实用的工具,它可以帮助我们更好地组…

H264码流插入和读取自定义数据(SEI字段)

目录 1. 前言2. H264码流结构2.1 文字说明2.2 码流格式图解 3. 自定义数据封装以及H264码流插入3.1 将自定义数据封装成SEI字段通用格式即可插入H264码流中3.2 编码逻辑 4. 代码5. 总结 1. 前言 本文主要记录,如何在已有的H264码流中插入自定义的数据,并…

商家说:我的对讲机能通话10公里、50公里,你敢信吗?

有不少渠道经销商,在日常经营中往往会遇到用户的经典四问: 您家的对讲机通话距离远吗?待机时间长吗?功能多吗?经得住摔吗? 对讲机用户常问的问题 对于后三问,通常还有电池电量、技术规格、功能…

查找ABAP代码

SE38执行:RS_ABAP_SOURCE_SCAN/RPR_ABAP_SOURCE_SCAN 批量查找字符串使用位置

互联网工程师 Java 面试题及答案整理(2023 速成版,7 天就能吃透)

现在 Java 面试都只是背答案吗? 不背就通过不了面试,但是现在面试都问原理、问场景!Java 面试题就像我们高考时的文言文,包括古诗词,不背是不可能答出来的!当然了,除了背,还得理解&…

全网最牛,性能测试超全流程总结整理,你都遗漏了什么...

目录:导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜) 前言 1、性能需求分析 …

Jenkins自动化构建

自动化构建 Jenkins 是一款开源 CI&CD 软件,用于自动化各种任务,包括构建、测试和部署软件 Jenkins 支持各种运行方式,可通过系统包、Docker 或者通过一个独立的 Java 程序 安装依赖 安装参考:Windows环境下安装Jenkins **…

解锁市场潜力:海外网红营销效果最大化的7个关键步骤

在当今数字化时代,海外网红营销已经成为许多企业推广产品和品牌的重要手段。通过与海外网红合作,品牌可以有效地扩大影响力和受众群体,并提升产品或服务的认知度。然而,要实现海外网红营销效果最大化,并不是一件轻而易…

一元函数微分学中导数--定义--意义--基本公式--运算法则

目录 导数的定义 左导数和右导数 导数的几何意义和物理意义 几何意义 导数的几何意义--切线的斜率 物理意义 导数的物理意义——瞬时速度 基本初等函数导数公式 基本初等函数 常用基本初等函数导数公式 导数求解的四则运算法则 函数的求导法则 复合函数求导法则 导…

Linux驱动入门(五)——构建第一个驱动程序

文章目录 前言开发环境配置之内核升级为什么升级内核内核升级 Hello world 驱动程序驱动模块的组成Hello World模块编译Hello World模块模块的操作Hello World模块加载后文件系统的变化 模块参数和模块之间通信模块参数模块的文件格式ELF模块之间的通信模块之间的通信实例 将模…

RHEL 9 新特性及技术演示

OpenSSH:新增禁止 root 的密码登录 Cockpit:RHEL 的 Web 控制台 DNF-3:软件安装方法 NetworkManager:网络管理的主要组件 Nftables:默认的用户空间防火墙 WireGuard:快速、安全的 VPN 隧道&#xff08…

阿里架构师珍藏版“亿级高并发系统设计手册(2023 版)”

高并发 俗话说:罗马不是一天建成的,系统的设计当然也是如此。 从原来谁都不看好的淘宝到现在的电商巨头,展现的不仅仅是一家互联网巨头的兴起,也是国内互联网行业迎来井喷式发展的历程,网络信号从 2G 发展到现在的 5…

【计算机图形学】期末复习Bezier曲线与曲面篇

【计算机图形学】期末复习Bezier曲线与曲面篇 文章目录 【计算机图形学】期末复习Bezier曲线与曲面篇一、Bezier曲线的定义二、一次Bezier曲线(直线)三、二次Bezier曲线(抛物线)四、三次Bezier曲线(自由曲线&#xff0…

高效地将 TailwindCSS 与 Nuxt 结合使用

在这篇文章中,我们将了解如何在 TailwindCSS 的官方 Nuxt 模块的帮助下有效地将 TailwindCSS 与 Nuxt 应用程序结合使用。我们还将了解如何将 SVG 图标与 TailwindCSS 一起使用,而不是直接使用图像或 SVG 图标,以及如何基于给定图像为 Tailwi…

总结5种常用加密算法

前言 在平时的工作中,可能也在很多地方用到了加密、解密,比如: 用户的密码不能明文存储,要存储加密后的密文 用户的银行卡号、身份证号之类的敏感数据,需要加密传输 还有一些重要接口,比如支付&#xff0…

Linux conda 环境迁移 服务器之间迁移

网上很多方法语焉不详,本文主要介绍在Linux系统之间进行单一环境迁移,从服务器A迁移到服务器B的两种方式: conda list方式进行Linux系统在线环境迁移拷贝envs方式进行Linux系统离线环境迁移 conda list方式 迁移完毕后需要手动安装缺失的py…