上位机图像处理和嵌入式模块部署(树莓派4b与消息分发)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】

        和多线程相比较,多进程最大的好处就是安全。一个进程挂了,不影响其他进程的运行。但是多线程也有自己的优点,那就是数据共享和消息传递会比较快。比如说,如果一个消息需要分发到不同的插件里面,这个时候在多线程下面就特别好实现。一般这种情况下,我们会创建若干个线程,不同的业务模块当成plugin插入进来,如果哪个plugin有消息需要处理,那么就从线程池找到一个线程,bind到特定的plugin来处理。处理完了,如果有其他的plugin需要处理,就继续处理其他的plugin。

        当这个plugin有bug的时候,还可以卸载、重新加载,毕竟是以显式动态库的形式加载的。这就是多线程的优势。这个时候线程的接收和发送,也可以做成一个插件。我们这里为了简便,用一个int数据来代替,实际使用的使用会稍微复杂一点。

1、初始化空间

        这里采用了静态空间来处理数据。另外有三个量比较关键,分别是startPos、endPos和cnt。其中当startPos=endPos的时候,只有两种情况,要么一个数据没有,要么数据已经存满。所以这种情况下,需要一个cnt来判别一下。

#include <iostream>
#include <cassert>
using namespace std;

// share memory access method
#define MAX_NUM 256

static int dataBuf[MAX_NUM];
static int startPos = 0;
static int endPos = 0; // ebdPos = startPos only when empty or full
static int cnt = 0; // very important

2、使用锁

        对于数据的创建和保存,一般存在并发的可能性,所以这个时候,需要一个添加锁、释放锁的操作。这里使用了空函数,大家可以根据自己的使用情况补充完整。

static void lock() // for lock method
{
	return;
}

static void unlock() // for unlock method
{
	return;
}

3、存储数据

        当我们收到一个消息,需要群发到其他模块的时候,就会调用这个函数,

bool putData(int data) // put data here
{
	lock();
	if (cnt == MAX_NUM)
	{
		unlock();
		return false;
	}

	dataBuf[startPos] = data;
	startPos = (startPos + 1) % MAX_NUM;
	cnt += 1;
	unlock();
	return true;
}

4、获取数据

        获取数据的动作对于plugin来说,一般都是不可见的。更常见的做法是,把接收到的消息和特定的函数做一个bind,这样消息来了之后直接调用对应的函数就可以了。

bool getData(int& data) // get data here
{
	lock();
	if (cnt == 0)
	{
		unlock();
		return false;
	}

	data = dataBuf[endPos];
	endPos = (endPos + 1) % MAX_NUM;
	cnt -= 1;
	unlock();
	return true;
}

5、测试和验证

        编写好了对应的函数,最好自己写一个单元测试确认一下,这样也比较放心一点。这有点类似于单元测试的编写,其实这是非常好的开发方法,只不过大家平时要么不太重视,要么因为工作量的原因,真正做的同学少之又少。

int main(int argc, char* argv[]) // function starts here
{
	int value = 10;
	assert(putData(value) == true);
	assert(startPos = 1);
	assert(cnt == 1);

	value = 0;
	assert(getData(value) == true);
	assert(value == 10);
	assert(endPos == 1);
	assert(cnt == 0);

	startPos = MAX_NUM - 1;
	endPos = MAX_NUM - 1;
	value = 100;
	assert(putData(value) == true);
	assert(startPos == 0);
	assert(cnt == 1);

	value = 0;
	assert(getData(value) == true);
	assert(value == 100);
	assert(endPos == 0);
	assert(cnt == 0);
	return 0;
}

6、拓展和补充       

        上面暂时只是int数据的压入和保存,如果是char数据的操作,会稍微复杂一点,因为有可能会超过内存可能会超过界限往回写,这样需要写的时候注意下。

#include <iostream>
#include <cstring>
using namespace std;

#define MAX_BUF_SIZE 4096
char dataBuf[MAX_BUF_SIZE];
int startPos = 0;
int endPos = 0;
int cnt = 0;

bool putData(char* pBuf)
{
	int size = *(int*)pBuf;

	if ((MAX_BUF_SIZE - cnt) < size)
	{
		return false;
	}

	if ((MAX_BUF_SIZE - startPos) > size)
	{
		memmove((void*)&dataBuf[startPos], pBuf, size);
		startPos += size;
		cnt += size;
		return true;
	}

	memmove((void*)&dataBuf[startPos], pBuf, MAX_BUF_SIZE - startPos);
	memmove((void*)&dataBuf[0], &pBuf[MAX_BUF_SIZE - startPos], size - (MAX_BUF_SIZE - startPos));
	startPos = size - (MAX_BUF_SIZE - startPos);
	cnt += size;
	return true;
}

bool getData(char* pBuf, int& size)
{
	char data[4];

	if (cnt == 0)
	{
		return false;
	}

	// get current size
	if (endPos <= (MAX_BUF_SIZE - 4))
	{
		size = *(int*)&dataBuf[endPos];
	}
	else
	{
		if (endPos == (MAX_BUF_SIZE - 3))
		{
			data[0] = dataBuf[endPos];
			data[1] = dataBuf[endPos + 1];
			data[2] = dataBuf[endPos + 2];
			data[3] = dataBuf[0];
		}
		else if (endPos == (MAX_BUF_SIZE - 2))
		{
			data[0] = dataBuf[endPos];
			data[1] = dataBuf[endPos + 1];
			data[2] = dataBuf[0];
			data[3] = dataBuf[1];
		}
		else
		{
			data[0] = dataBuf[endPos];
			data[1] = dataBuf[0];
			data[2] = dataBuf[1];
			data[3] = dataBuf[2];
		}
		size = *(int*)&data[0];
	}

	if ((MAX_BUF_SIZE - endPos) > size)
	{
		memmove(pBuf, (void*)&dataBuf[endPos], size);
		endPos += size;
		cnt -= size;
		return true;
	}

	memmove(pBuf, (void*)&dataBuf[endPos], MAX_BUF_SIZE - endPos);
	memmove(&pBuf[MAX_BUF_SIZE - endPos], (void*)&dataBuf[0], size - (MAX_BUF_SIZE - endPos));
	endPos = size - (MAX_BUF_SIZE - endPos);
	cnt -= size;
	return true;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Ex1-C6油气化工防爆轮式巡检机器人

Ex1系列防爆轮式巡检机器人整机采用防爆设计&#xff0c;防爆等级为Exd II CT4 Gb。机器人通过无轨3D形态导航技术&#xff0c;结合360度防爆云台和无线防爆充电桩&#xff0c;实现整套防爆标准&#xff0c;可广泛应用于石油、燃气、化工、冶金等II类爆炸环境中&#xff0c;代替…

程序员缓解工作压力——方法分享

前言 作为一名初级程序员&#xff0c;我承认自己在应对工作压力方面还有待提高。在日常工作中&#xff0c;我时常感到压力山大&#xff0c;尤其是在面对复杂问题或紧迫的项目期限时。然而&#xff0c;为了保持高效和持久的工作热情&#xff0c;我还是积极寻求并使用了一…

Python 贪吃蛇

文章目录 效果图&#xff1a;项目目录结构main.pygame/apple.pygame/base.pygame/snake.pyconstant.py 效果图&#xff1a; 项目目录结构 main.py from snake.game.apple import Apple # 导入苹果类 from snake.game.base import * # 导入游戏基类 from snake.game.snake im…

Linux之命令行参数与环境变量

命令行参数&环境变量 命令行参数 main函数也是一个函数&#xff0c;其实也可以携带参数的 int main( int argc, char *argv[ ], char *envp[ ] ) {program-statements } 那这里是有三个参数的: 第一个参数&#xff1a; argc 是个整型变量&#xff0c;表示命令行参数的个数…

WIFI/BT中蓝牙的硬件资源是如何调度的 UART和PCM接口传输的是什么信号

安卓或IOS手机中&#xff0c;wifi/bt中的蓝牙是如何调度硬件资源的&#xff0c;尤其是UART和PCM是如何分配的。M.2 wifi/bt模块或其他形式的模块中&#xff0c;蓝牙是如何调度硬件资源的&#xff0c;尤其是UART和PCM是如何分配的。今天我们就图文并茂的解决这个问题。 蓝牙文件…

SQL 基础 | AS 的用法介绍

SQL&#xff08;Structured Query Language&#xff09;是一种用于管理和操作数据库的标准编程语言。 在SQL中&#xff0c;AS关键字有几种不同的用法&#xff0c;主要用于重命名表、列或者查询结果。 以下是AS的一些常见用法&#xff1a; 重命名列&#xff1a;在SELECT语句中&a…

Vue生命周期都有哪些?

定义 Vue的生命周期就是实例从创建到销毁的一个过程&#xff0c;即从创建、初始化数据、编译模板、挂载Dom($el)->渲染、更新->渲染&#xff0c;卸载等一系列的过程。el是挂载点如<div id"app"></div>。 Vue的生命周期分为八个阶段 1.beforeCreate…

重看Spring聚焦BeanDefinition分析和构造

目录 一、对BeanDefinition的理解 &#xff08;一&#xff09;理解元信息 &#xff08;二&#xff09;BeanDefinition理解分析 二、BeanDefinition的结构设计分析 &#xff08;一&#xff09;整体结构体会 &#xff08;二&#xff09;重要接口和类分析 三、构造 BeanDef…

保姆级IDEA安装与配置教程(含视频+资料)

课程简介 本套课程主要针对 Java 基础开发相关的工具安装和使用&#xff0c;主要包含有 IDEA 的下载、安装、配置、使用、快捷键的使用等。 本套视频是作为新手最为实用的课程&#xff0c;IDEA 是 Java 企业级开发最为常用的继承开发环境。如果熟练使用 IDEA 的话&#xff0c…

【中断】【ARM64】学习总结

optee中的异常向量表解读–中断处理解读 https://mp.weixin.qq.com/s/gBsy4YDYTHGRsy2zcVr6Vg

c# winform快速建websocket服务器源码 wpf快速搭建websocket服务 c#简单建立websocket服务 websocket快速搭建

完整源码下载----->点击 随着互联网技术的飞速发展&#xff0c;实时交互和数据推送已成为众多应用的核心需求。传统的HTTP协议&#xff0c;基于请求-响应模型&#xff0c;无法满足现代Web应用对低延迟、双向通信的高标准要求。在此背景下&#xff0c;WebSocket协议应运而生…

Polardb集中式部署体验

前言说明 PolarDB是阿⾥云数据库团队⾃主开发的云原⽣数据库。据了解PolarDB是产品品牌统称&#xff0c;云上PolarDB提供了Polardb MySQL版&#xff08;集中式数据库&#xff09;&#xff0c;PolarDB PostgreSQL版&#xff08;集中式数据库&#xff09;和PolarDB分布式版&…

人工智能论文:BERT和GPT, GPT-2, GPT-3 的简明对比和主要区别

在BERT的论文里面&#xff1a; 2018.10 BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding&#xff0c;BERT已经解释了BERT&#xff0c;GPT&#xff0c;ELMo的区别。 *ELMo为双向RNN&#xff0c;请忽略。 主要区别&#xff1a; BERT使用的是…

机器学习:深入解析SVM的核心概念【四、软间隔与正则化】

软间隔与正则化 问题一&#xff1a;优化目标函数是如何得到的&#xff1f;得到的过程是怎样的&#xff1f;问题二&#xff1a;拉格朗日乘子法计算详细过程问题三&#xff1a;KKT条件求解过程问题四&#xff1a;结构风险最小化&#xff08;SRM&#xff09;的原理 在前面的讨论中…

批量视频剪辑新选择:一键式按照指定秒数分割视频并轻松提取视频中的音频,让视频处理更高效!

是否经常为大量的视频剪辑工作感到头疼&#xff1f;还在一个个手动分割、提取音频吗&#xff1f;现在&#xff0c;我们为你带来了一款全新的视频批量剪辑神器&#xff0c;让你轻松应对各种视频处理需求&#xff01; 首先&#xff0c;进入媒体梦工厂的主页面&#xff0c;并在板…

机器学习之基于Tensorflow(LSTM)进行多变量时间序列预测股价

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 项目简介&#xff1a;机器学习之基于TensorFlow&#xff08;LSTM&#xff09;进行多变量时间序列预测股价 一、项目…

【Java从入门到精通】Java 正则表达式

目录 正则表达式实例 &#x1f349;java.util.regex 包 &#x1f349;实例 &#x1f349;捕获组 &#x1f349;实例 &#x1f349;RegexMatches.java 文件代码&#xff1a; &#x1f349;正则表达式语法 &#x1f349;Matcher 类的方法 &#x1f349;索引方法 &#…

【Qt QML】QLibrary加载共享库中的类

QLibrary是一个用于加载动态链接库&#xff08;或称为共享库&#xff09;的类。它提供了一种独立于平台的方式来访问库中的功能。 在QLibrary中&#xff0c;可以通过构造函数或setFileName()方法设置要加载的库文件名。当加载库文件时&#xff0c;QLibrary会搜索所有平台特定的…

消失的VCC和VEE,取而代之的VDD和VSS

一直以来&#xff0c;这些电源电压&#xff08;Vdd 和 Vss&#xff09;或&#xff08;Vcc 和 Vee&#xff09;的命名都有点耐人寻味&#xff0c;甚至令人困惑。但为什么呢&#xff1f; It has always been a bit intriguing and even confusing the nomenclature of these powe…

Unreal 编辑器工具 批量重命名资源

右键 - Editor Utilities - Editor Utility Blueprint&#xff0c;基类选择 Asset Action Utility 在类默认值内&#xff0c;可以添加筛选器&#xff0c;筛选指定的类型 然后新建一个函数&#xff0c;加上4个输入&#xff1a;ReplaceFrom&#xff0c;ReplaceTo&#xff0c;Add…