建筑招聘网站哪个好,网站设计与管理论文,wordpress修改配置,eclipse视频网站开发这里描述如何使用数组字段内存管理特定。这使得数组数据能够被移入和移出waveform#xff0c;aai和aao类型的值字段(BPTR)。
使用这种特定包括用另一个(用户分配的)字段替代存储在BPTR字段的指针。基本规则是#xff1a;
1、BPTR以及它当前指向的内存#xff0c;只能在这个…这里描述如何使用数组字段内存管理特定。这使得数组数据能够被移入和移出waveformaai和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.hstatic 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(curellFirst(allPvt); cur; curellNext(cur)){struct devicePvt *priv CONTAINER(cur, struct devicePvt, node);epicsThreadMustCreate(wfworker,epicsThreadPriorityHigh,epicsThreadGetStackSize(epicsThreadStackSmall),worker, priv);}
}static void worker(void* raw)
{struct devicePvt *privraw;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(i0; inbytes/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 *privprec-dpvt;if(!priv){return 0;}*scan priv-scan;
/* 当这个线程被放入I/O扫描列表时唤醒这个worker*/if(dir0){// 发出事件信号epicsEventSignal(priv-wakeup);}return 0;
}static long read_wf(waveformRecord *prec)
{struct devicePvt *privprec-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,TESTTEST)
启动这个IOC程序并且查看加载的记录实例
epics dbl
TEST:wf
用cainfo和camonitor通道访问进行测试
rootorangepi4-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
rootorangepi4-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记录中数组值每秒钟随机变化一次。