当前位置: 首页 > news >正文

如何避免用waveformRecord复制数组

这里描述如何使用数组字段内存管理特定。这使得数组数据能够被移入和移出waveform,aai和aao类型的值字段(BPTR)。

使用这种特定包括用另一个(用户分配的)字段替代存储在BPTR字段的指针。基本规则是:

1、BPTR以及它当前指向的内存,只能在这个记录被锁定时才能被访问。

2、NELM不可以被更改。

3、BPTR必须总是指向一段足够大的内存,来装下最大的元素数目(由NELM字段确定)。

规则1意味着从一个设备支持函数或者手动调用dbScanLock()后读,写或者解引用BPTR字段才安全。规则3意味着BPTR不能被设置NULL,并且在替代BPTR时,替换必须为最差情况分配足够大空间。一个外部客户端能够在几乎任何时间写入一个最大NELM个元素的数组。

以下示例演示了为waveform缓存使用了自定义分配。

以下是一个waveform记录设备支持的源代码devwf.c:

#include  "errlog.h"
#include "initHooks.h"
#include "ellLib.h"
#include "devSup.h"
#include "dbDefs.h"
#include "dbAccess.h"
#include "cantProceed.h"
#include "epicsTypes.h"
#include "epicsMutex.h"
#include "epicsEvent.h"
#include "epicsThread.h"
#include "menuFtype.h"
#include "dbScan.h"
#include "alarm.h"
#include "recGbl.h"
#include "waveformRecord.h"
#include "epicsExport.h"static ELLLIST allPvt = ELLLIST_INIT;struct devicePvt {ELLNODE node;/* 同步访问这个结构体 */epicsMutexId lock;/* 当需要另一个更新时,唤醒这个worker */epicsEventId wakeup;/* 当另一个更新可用时,通知scanner线程。 */IOSCANPVT scan;/* 下次更新 */void *nextBuffer;epicsUInt32 maxbytes, numbytes;
};static long init(int phase);
static long init_record(dbCommon *pcommon);
static long get_iointr_info(int dir, dbCommon *prec, IOSCANPVT *scan);
static long read_wf(waveformRecord *prec);
static void worker(void*);
static void startWorkers(initHookState);wfdset devWfZeroCopy = {{5, NULL, init, init_record, get_iointr_info},read_wf
};epicsExportAddress(dset, devWfZeroCopy);static long init(int phase)
{if(phase!=0){return 0;}initHookRegister(&startWorkers);return 0;
}static long init_record(dbCommon *pcommon)
{struct devicePvt *priv;waveformRecord * prec = (waveformRecord *)pcommon;if(prec->ftvl!=menuFtypeSHORT) {errlogPrintf("%s.FTVL must be set to SHORT for this example\n", prec->name);return 0;}/* 清理由记录支持分配的数组。
*  由于我们使用lcalloc()/free(),不必要,
*  但用其它方法分配时,不需要。
*/free(prec->bptr);prec->bptr = callocMustSucceed(prec->nelm, dbValueSize(prec->ftvl), "first buf");// struct devicePvtpriv = callocMustSucceed(1, sizeof(*priv), "init_record devWfZeroCopy");priv->lock = epicsMutexMustCreate();priv->wakeup = epicsEventMustCreate(epicsEventFull);scanIoInit(&priv->scan);priv->maxbytes = prec->nelm*dbValueSize(prec->ftvl);ellAdd(&allPvt, &priv->node);prec->dpvt = priv;return 0;
}static void startWorkers(initHookState state)
{ELLNODE *cur;/*  直到调用scanIoRequest安全,才启动worker线程  */if(state!=initHookAfterInterruptAccept){return;}for(cur=ellFirst(&allPvt); cur; cur=ellNext(cur)){struct devicePvt *priv = CONTAINER(cur, struct devicePvt, node);epicsThreadMustCreate("wfworker",epicsThreadPriorityHigh,epicsThreadGetStackSize(epicsThreadStackSmall),&worker, priv);}
}static void worker(void* raw)
{struct devicePvt *priv=raw;void *buf = NULL;epicsUInt32 nbytes = priv->maxbytes;while(1) {epicsThreadSleep(1.0);if(!buf) {/* 为之后(本地)使用分配并且初始化一个新缓存 */size_t i;epicsInt16 *ibuf;buf = callocMustSucceed(1, nbytes, "buffer");ibuf = (epicsInt16*)buf;for(i=0; i<nbytes/2; i++)// 字节数除以2,就是元素数目{ibuf[i] = rand();}}/*  当扫描是'I/O Intr'时,等待事件信号,*   而当记录是周期扫描时,等待超时*/// 等待事件priv-wakeup 1.0秒,如果返回事件出错,挂起正在运行的线程if(epicsEventWaitWithTimeout(priv->wakeup, 1.0)==epicsEventError) {cantProceed("worker encountered an error waiting for wakeup\n");}// 获取互斥锁priv->lockepicsMutexMustLock(priv->lock);if(!priv->nextBuffer) {/* 使得本地缓存对read_wf函数可用 */priv->nextBuffer = buf;buf = NULL;priv->numbytes = priv->maxbytes;scanIoRequest(priv->scan);}epicsMutexUnlock(priv->lock);}
}static long get_iointr_info(int dir, dbCommon *prec, IOSCANPVT *scan)
{struct devicePvt *priv=prec->dpvt;if(!priv){return 0;}*scan = priv->scan;
/* 当这个线程被放入I/O扫描列表时,唤醒这个worker*/if(dir==0){// 发出事件信号epicsEventSignal(priv->wakeup);}return 0;
}static long read_wf(waveformRecord *prec)
{struct devicePvt *priv=prec->dpvt;if(!priv){return 0;}epicsMutexMustLock(priv->lock);if(priv->nextBuffer) {/* 更新可用,所以占用它 */if(prec->bptr){// 指向数据区的指针有效,释放此数据区free(prec->bptr);prec->bptr = priv->nextBuffer; /* 切换指针指向,没有复制内存 */priv->nextBuffer = NULL;prec->nord = priv->numbytes / dbValueSize(prec->ftvl);// 计算实际元素数目epicsEventSignal(priv->wakeup);// 工作线程又可以运行}epicsMutexUnlock(priv->lock);assert(prec->bptr);}return 0;
}/*typedef long (*DEVSUPFUN)(void *);typedef struct dset {    //设备支持入口表long        number;      //支持例程数目DEVSUPFUN   report;      // 打印报告DEVSUPFUN   init;        // init支持层DEVSUPFUN   init_record; // 特定记录的init设备DEVSUPFUN   get_ioint_info; // 获取io中断信息//以下时取决于记录的其它函数
} dset;
*/

编写以上源文件的devwfsup.dbd文件:

device(waveform,CONSTANT,devWfZeroCopy,"Zero Copy Demo")

在Makefile文件中添加以上两个文件:

wfDevSup_DBD += devwfsup.dbd
wfDevSup_SRCS += devwf.c

添加一个只含一个waveform记录的db文件:

record(waveform, "$(TEST):wf") {field(DTYP, "Zero Copy Demo")field(FTVL, "SHORT")field(NELM, "6")field(SCAN, "I/O Intr")
}

更改启动文件st.cmd:

dbLoadRecords("db/wf.db","TEST=TEST")

启动这个IOC程序,并且查看加载的记录实例:

epics> dbl
TEST:wf

用cainfo和camonitor通道访问进行测试:

root@orangepi4-lts:/usr/local/EPICS/base/modules/database/src/std/dev# cainfo  TEST:wf
TEST:wfState:            connectedHost:             192.168.50.184:5064Access:           read, writeNative data type: DBF_SHORTRequest type:     DBR_SHORTElement count:    6
root@orangepi4-lts:/usr/local/EPICS/base/modules/database/src/std/dev# camonitor TEST:wf
TEST:wf 2023-08-11 04:38:32.964899 6 11358 -32429 28512 -25174 -11566 -30030
TEST:wf 2023-08-11 04:38:33.965274 6 27856 32389 -2566 -12204 2520 14133
TEST:wf 2023-08-11 04:38:34.965634 6 -19224 -17196 29030 19074 -11420 -20584
TEST:wf 2023-08-11 04:38:35.966003 6 -17959 -21592 -25977 -20875 -3483 10352
TEST:wf 2023-08-11 04:38:36.966368 6 29274 10378 -18625 -19358 -18816 4905
TEST:wf 2023-08-11 04:38:37.966640 6 28740 -7458 -27524 -8283 -32631 26446

TEST:wf记录中数组值每秒钟随机变化一次。

相关文章:

如何避免用waveformRecord复制数组

这里描述如何使用数组字段内存管理特定。这使得数组数据能够被移入和移出waveform&#xff0c;aai和aao类型的值字段(BPTR)。 使用这种特定包括用另一个(用户分配的)字段替代存储在BPTR字段的指针。基本规则是&#xff1a; 1、BPTR以及它当前指向的内存&#xff0c;只能在这个…...

RocketMQ 延迟消息

RocketMQ 延迟消息 RocketMQ 消费者启动流程 什么是延迟消息 RocketMQ 延迟消息是指&#xff0c;生产者发送消息给消费者消息&#xff0c;消费者需要等待一段时间后才能消费到。 使用场景 用户下单之后&#xff0c;15分钟未支付&#xff0c;对支付账单进行提醒或者关单处理…...

Dex文件混淆(一):BlackObfuscator

Dex文件混淆(一)&#xff1a;BlackObfuscator 首发地址:http://zhuoyue360.com/crack/105.html 文章目录 Dex文件混淆(一)&#xff1a;BlackObfuscator1. 前言2.小试牛刀3. 参考学习1. dex2jar源码简析2. BlackObfuscator简析1. 控制流平坦化1. 控制流平坦化基本介绍 2. Dex解析…...

Linux下编译arm 32 出错(/bin/bash: arm-none-linux-gnueabi-gcc: command not found )

一、arm-none-linux-gnueabi-gcc不能再64位系统下下编译ARM的32位库的问题解决方法如下&#xff1a; sudo apt-get install lib32stdc6 sudo apt-get install lib32ncurses5 sudo apt-get install lib32z1 二、交叉编译工具没有写入环境变量或写错&#xff0c;重新写入环境变量…...

最近遇到的两个小问题总结:git问题和node问题

这两个问题都是我帮别人看问题的解决的&#xff0c;在windows系统上遇到的&#xff1a; 1、git没有配置全局变量 在使用git的时候&#xff0c;报’git‘不是内部或外部命令&#xff0c;也不是可运行的程序。然后再在其他文件下面试一下&#xff08;git --version&#xff09;…...

Java # Spring(1)

一、概念 1、核心技术&#xff1a;依赖注入&#xff08;DI&#xff09;&#xff0c;AOP&#xff0c;事件&#xff08;events&#xff09;&#xff0c;资源&#xff0c;i18n&#xff0c;验证&#xff0c;数据绑定&#xff0c;类型转换&#xff0c;SpEL。 2、测试&#xff1a;模…...

SCL更换阿里数据源

问题&#xff1a; zabbix安装前端环境报错 yum install zabbix-web-mysql-scl zabbix-apache-conf-scl -y 报错&#xff1a;Could not retrieve mirrorlist http://mirrorlist.centos.org/ 能上网 但是不能ping通http://mirrorlist.centos.org/ 解决&#xff1a; 修改repo数…...

【web逆向】全报文加密流量的去加密测试方案

aHR0cHM6Ly90ZGx6LmNjYi5jb20vIy9sb2dpbg 国密混合 WEB JS逆向篇 先看报文&#xff1a;请求和响应都是全加密&#xff0c;这种情况就不像参数加密可以方便全文搜索定位加密代码&#xff0c;但因为前端必须解密响应的密文&#xff0c;因此万能的方法就是搜索拦截器&#xff0c…...

Django实现音乐网站 ⑼

使用Python Django框架制作一个音乐网站&#xff0c; 本篇主要是后台对专辑、首页轮播图原有功能的基础上进行部分功能实现和显示优化。 目录 专辑功能优化 新增编辑 专辑语种改为下拉选项 添加单曲优化显示 新增单曲多选 更新歌手专辑数、专辑单曲数 获取歌手专辑数 保…...

【脚踢数据结构】

(꒪ꇴ꒪ )&#xff0c;Hello我是祐言QAQ我的博客主页&#xff1a;C/C语言,Linux基础,ARM开发板&#xff0c;软件配置等领域博主&#x1f30d;快上&#x1f698;&#xff0c;一起学习&#xff0c;让我们成为一个强大的攻城狮&#xff01;送给自己和读者的一句鸡汤&#x1f914;&…...

uni-app使用vue语法进行开发注意事项

目录 uni-app 项目目录结构 生命周期 路由 路由跳转 页面栈 条件编译 文本渲染 样式渲染 条件渲染 遍历渲染 事件处理 事件修饰符 uni-app 项目目录结构 组件/标签 使用&#xff08;类似&#xff09;小程序 语法/结构 使用vue 具体项目目录如下&#xff1a; 生命…...

数据结构---B树

目录标题 B-树的由来B-树的规则和原理B-树的插入分析B-树的插入实现准备工作find函数insert中序遍历 B-树的性能测试B-树的删除B树B树的元素插入B*树的介绍 B-树的由来 在前面的学习过程中&#xff0c;我们见过很多搜索结构比比如说顺序查找&#xff0c;二分查找&#xff0c;搜…...

c++11以后c++标准库定义的固定位宽的整数类型(Fixed width integer types)

Fixed width integer types Fixed width integer types (since C11) - cppreference.com 相关定义文件如下&#xff1a; Windows系统MSVC: Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.33.31629\include\cstdint Linux系统GCC: gcc\libstdc-v3\include\c_g…...

Object.values()

Object.values() 是ES2017新增的一个对象方法,它可以将一个对象自身的所有可枚举属性值,组成一个数组返回。 基本语法: Object.values(obj)示例: jsCopy codeconst obj {foo: bar,baz: 42 };Object.values(obj); // [bar, 42]Object.values()的特点: 只返回可枚举的属性值…...

Oracle 开发篇+Java调用OJDBC访问Oracle数据库

标签&#xff1a;JAVA语言、Oracle数据库、Java访问Oracle数据库释义&#xff1a;OJDBC是Oracle公司提供的Java数据库连接驱动程序 ★ 实验环境 ※ Oracle 19c ※ OJDBC8 ※ JDK 8 ★ Java代码案例 package PAC_001; import java.sql.Connection; import java.sql.ResultSet…...

linux 查询后台任务及杀掉进程

查看后台任务命令 jobs -l删除后台进程命令 kill -9 28719...

【Vue3 博物馆管理系统】使用Vue3、Element-plus菜单组件构建前台用户菜单

系列文章目录 第一章 定制上中下&#xff08;顶部菜单、底部区域、中间主区域显示&#xff09;三层结构首页 第二章 使用Vue3、Element-plus菜单组件构建菜单 [第三章 使用Vue3、Element-plus菜单组件构建轮播图] [第四章 使用Vue3、Element-plus菜单组件构建组图文章] 文章目…...

Windows 11清除无效、回收站、过期、缓存、补丁更新文件

Windows 11与之前的Windows版本类似&#xff0c;也需要定期清理无效、垃圾、过期、缓存文件来保持系统性能和存储空间的优化。以下是在Windows 11中进行这些清理操作的一些建议方法&#xff1a; 磁盘清理工具 Windows 11内置了磁盘清理工具&#xff0c;可以帮助你删除临时文件…...

栈和队列详解(2)

目录 一、什么是队列&#xff1f; 二、创建一个我们自己的队列 1.前置准备 1.1需要的三个文件 1.2结构体的创建和头文件的引用 2.接口的实现 2.1初始化队列 2.2入队 2.3队列元素个数和判空 2.4取队头元素和队尾元素 2.5出队 2.6摧毁队列 2.7测试接口 三、所有代码 1.…...

EMC传导干扰滤波电路设计

1.EMC概念 2.EMC 传导干扰详解 EMC传导滤波电路的设计--传导干扰详解 3.EMC 传导干扰的测量方法 4.EMC 滤波电路设计 5.浪涌抑制电路设计 6.开关电源的安全要求 7.当前开关电源灯的应用...

工业安全零事故的智能守护者:一体化AI智能安防平台

前言&#xff1a; 通过AI视觉技术&#xff0c;为船厂提供全面的安全监控解决方案&#xff0c;涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面&#xff0c;能够实现对应负责人反馈机制&#xff0c;并最终实现数据的统计报表。提升船厂…...

python/java环境配置

环境变量放一起 python&#xff1a; 1.首先下载Python Python下载地址&#xff1a;Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个&#xff0c;然后自定义&#xff0c;全选 可以把前4个选上 3.环境配置 1&#xff09;搜高级系统设置 2…...

1688商品列表API与其他数据源的对接思路

将1688商品列表API与其他数据源对接时&#xff0c;需结合业务场景设计数据流转链路&#xff0c;重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点&#xff1a; 一、核心对接场景与目标 商品数据同步 场景&#xff1a;将1688商品信息…...

将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?

Otsu 是一种自动阈值化方法&#xff0c;用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理&#xff0c;能够自动确定一个阈值&#xff0c;将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...

Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!

一、引言 在数据驱动的背景下&#xff0c;知识图谱凭借其高效的信息组织能力&#xff0c;正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合&#xff0c;探讨知识图谱开发的实现细节&#xff0c;帮助读者掌握该技术栈在实际项目中的落地方法。 …...

WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)

一、Solidity合约开发 下面是 Solidity 合约开发 的概念、代码示例及讲解&#xff0c;适合用作学习或写简历项目背景说明。 &#x1f9e0; 一、概念简介&#xff1a;Solidity 合约开发 Solidity 是一种专门为 以太坊&#xff08;Ethereum&#xff09;平台编写智能合约的高级编…...

python执行测试用例,allure报乱码且未成功生成报告

allure执行测试用例时显示乱码&#xff1a;‘allure’ &#xfffd;&#xfffd;&#xfffd;&#xfffd;&#xfffd;ڲ&#xfffd;&#xfffd;&#xfffd;&#xfffd;ⲿ&#xfffd;&#xfffd;&#xfffd;Ҳ&#xfffd;&#xfffd;&#xfffd;ǿ&#xfffd;&am…...

接口自动化测试:HttpRunner基础

相关文档 HttpRunner V3.x中文文档 HttpRunner 用户指南 使用HttpRunner 3.x实现接口自动化测试 HttpRunner介绍 HttpRunner 是一个开源的 API 测试工具&#xff0c;支持 HTTP(S)/HTTP2/WebSocket/RPC 等网络协议&#xff0c;涵盖接口测试、性能测试、数字体验监测等测试类型…...

pgsql:还原数据库后出现重复序列导致“more than one owned sequence found“报错问题的解决

问题&#xff1a; pgsql数据库通过备份数据库文件进行还原时&#xff0c;如果表中有自增序列&#xff0c;还原后可能会出现重复的序列&#xff0c;此时若向表中插入新行时会出现“more than one owned sequence found”的报错提示。 点击菜单“其它”-》“序列”&#xff0c;…...

基于开源AI智能名片链动2 + 1模式S2B2C商城小程序的沉浸式体验营销研究

摘要&#xff1a;在消费市场竞争日益激烈的当下&#xff0c;传统体验营销方式存在诸多局限。本文聚焦开源AI智能名片链动2 1模式S2B2C商城小程序&#xff0c;探讨其在沉浸式体验营销中的应用。通过对比传统品鉴、工厂参观等初级体验方式&#xff0c;分析沉浸式体验的优势与价值…...