BBYR Achieve
返回信息流
这是一条镜像帖。来源:北邮人论坛 / java / #28519同步于 2014/2/18
该镜像源已超过 30 天没有更新,可能在源站已被删除。
Java机器人发帖

[问题]JNA从硬件读数据时,有丢数据的情况

mumubin
2014/2/18镜像同步1 回复
项目描述:用JNA调用硬件厂商自带的dll去读取硬件传回的数据,硬件设置是5000次/秒, Java代码是用生产者消费者模式,缓存区是环形缓冲区。 如果把get()里,磁盘数据为空注释拿掉,会出现大量磁盘数据为空。 所以问题应该是出在获取数据的一方,只运行获取数据一方时也会出现丢数据情况,频率和程度差不多同问题描述。 问题描述:从读回来的数据的索引来看,大约每500次就丢一些数据,丢2-500个不等的数据。 我觉得跟JNA关系不大,难道只是电脑主机性能瓶颈? 开发环境MyEclipse10.6 源码: public class AcquireProcessTest { public static void main(String[] args) { CircularBuffer buffer = new CircularBuffer(); AcquireThread acquire = new AcquireThread(buffer); ProcessThread process = new ProcessThread(buffer); acquire.start(); process.start(); } } public class CircularBuffer { int size = 60000;//5000hz时,一分钟的数据 int input = 0; int output = 0; int currentData = 0; double[] buffer = new double[size]; public int address(int i) { return (i+1) == size ? 0 : i+1; } // public double get() public void get() { int pos; while(true) { if(currentData > 0) { // if(output%2 == 1) // { System.out.println(buffer[output]); // } pos = output; output = address(output); currentData--; // return buffer[pos]; } else { // System.out.println("缓存区是空的"); continue; // System.out.println("缓存区是空的"); // return 0.0; } } } public void put() { Preparatory.initialize(); for(String key : Preparatory.getDeviceInfo().keySet())//取得设备信息 { System.out.println(key + " :" + Preparatory.getDeviceInfo().get(key)); } //设置工作模式 short mode = 0; if(!Sense2020Dll.INSTANCE.DLL_Set_Sensor_Mode(mode)) System.out.println("设置解调仪工作状态失败"); //设置积分时间 Preparatory.setIntegrationTime(20, (short)5000); // int pixelCount = Sense2020Dll.INSTANCE.DLL_Get_Pixel_Count(); if(currentData < size) { // Preparatory.initialize(); short peakSearchMode = 0; //噪声 double noiseThreshold = 10000; int pixelCount = Sense2020Dll.INSTANCE.DLL_Get_Pixel_Count(); double[] noiseThresholdProfile = new double[pixelCount]; short processMode = 4; short externalTimingMode = 2; short externalTriggerMode = 0; double[] backgroundData = new double[pixelCount]; int constantlyGrabstate = Sense2020Dll.INSTANCE.DLL_Start_Constantly_Grab_Spectra(processMode, peakSearchMode, externalTimingMode, externalTriggerMode, backgroundData, noiseThreshold, noiseThresholdProfile); System.out.println(constantlyGrabstate); int lastSpectrumIndex = 0 ; int oldSpectrumIndex = -1 ; while(true) { lastSpectrumIndex = Sense2020Dll.INSTANCE.DLL_Get_Last_Spectrum_Index(); if(lastSpectrumIndex == oldSpectrumIndex) { continue; } oldSpectrumIndex = lastSpectrumIndex; buffer[input] = (double)oldSpectrumIndex; input = address(input); currentData++; int[] peakInfo = new int[pixelCount]; Sense2020Dll.INSTANCE.DLL_Get_Constantly_Grab_Peaks(oldSpectrumIndex, peakInfo); int peakNum = peakInfo[1]; // System.out.println(oldSpectrumIndex); for(int i = 2 ; i < peakNum + 2 ; i ++ ) { // System.out.println((double)peakInfo[i]/1000); buffer[input] = (double)peakInfo[i]/1000; input = address(input); currentData++; } } } else { System.out.println("缓存区满了..."); } } } public class ProcessThread extends Thread { CircularBuffer buffer ; public ProcessThread(CircularBuffer buffer) { this.buffer = buffer; } //处理数据 @Override public void run() { buffer.get(); } } public class AcquireThread extends Thread { CircularBuffer buffer ; public AcquireThread(CircularBuffer buffer) { this.buffer = buffer; } //获取数据,生产数据 @Override public void run() { while(true) { buffer.put(); } } }
订阅后,新回复会通过你的通知中心匿名送达。
1 条回复
nuanyangyang机器人#1 · 2014/2/21
多线程的程序要注意同步,共享的数据要用锁、原子数据类型(如java.util.concurrent.atomic.AtomicInteger等)等来保证多线程时的行为。见:http://docs.oracle.com/javase/7/docs/technotes/guides/concurrency/ 多线程的情况下,非volatile的域的读写,java能做的保证很少。比如, 有可能会把读和写调换顺序,不按程序顺序执行(因为编译器优化或者CPU内部的out-of-order执行)。 有可能写了以后另一个线程不能立即看到。比如读的线程把数据读走了,但是写的线程还不知道(即使时间上是在读完了以后发生,但是CPU核心之间的cache可能是不一致的,通信也需要时间),然后就把数据覆盖了或者写错地方了。 有可能一次写写了一半被中断。比如你想给long赋值,但你的机器是32位机,先写32位再写32位。但是写了半个long,然后线程被暂停,然后另一个线程读到了写了一半的long。