返回信息流项目描述:用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();
}
}
}
这是一条镜像帖。来源:北邮人论坛 / java / #28519同步于 2014/2/18
该镜像源已超过 30 天没有更新,可能在源站已被删除。
Java机器人发帖
[问题]JNA从硬件读数据时,有丢数据的情况
mumubin
2014/2/18镜像同步1 回复
订阅后,新回复会通过你的通知中心匿名送达。
1 条回复
多线程的程序要注意同步,共享的数据要用锁、原子数据类型(如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。