我正在尝试使用java在并行端口上创建方波。到目前为止,我有这个实现。
public class Wave extends Thread {
public Wave() {
super();
setPriority(MAX_PRIORITY);
}
@Override
public void run() {
Wave.high();
LockSupport.parkNanos(20000000);
Wave.low();
LockSupport.parkNanos(20000000);
}
public static native void high();
public static native void low();
}
使用JNI实现high()和low()(共享C库控制并行端口)。它工作得很好;它产生一个周期约为40ms的方波。使用示波器,当计算机空闲时,标准偏差大约为10微秒。当计算机没有空闲时,标准偏差变得更大。我认为这是因为更多的上下文切换发生并且线程在等待状态下保持太长时间并且未能准确地实现指定的20 ms。
有没有办法让我的实施更准确?我知道我可以使用硬件,但我想知道我是否也可以使用软件。
一个选项是"听"到一个时钟并执行一个时间到毫秒的动作?
答案 0 :(得分:1)
只是“监听”时钟并不能解决导致抖动的上下文切换问题。
如果您可以将核心专用于此:
System.nanoTime()
或RDTS
/RDTSCP
),并根据需要调用high()
/ low()
。这样你就可以实现非常低的抖动。
当然,如果任务是简单地产生方波,那么计算资源的使用效率就会非常低。
答案 1 :(得分:1)
我认为会有两种抖动来源。
首先,java中的垃圾收集(以及可能的其他后台进程,如JIT)。对于您提供的代码,不应该有任何gc。但如果这是一个更大的系统的一部分,那么你可能会发现需要垃圾收集,并且它可能会改变它运行时的时间。您可以尝试使用jvm设置(java -X)来改善这一点。
第二,系统调度程序。除了aix的建议之外,你可以提高流程的优先级并进行一些特定于linux的调整。 this article解释了linux的一些问题。 ubuntu has a low-latency kernel,您可以安装,但我无法找到它实际包含的内容的信息,因此您可以在其他系统上执行相同操作(更新:我认为它可能包含this patch)。如果你想寻找更多信息“低延迟”是搜索的关键思考,那些在linux上进行音频处理的人往往是最关心这一点的人。)
答案 2 :(得分:0)
如果您的上下文切换不会造成太多延迟,您可以尝试将线程停放到给定时间,而不是在给定时间间隔内停止:
public class Wave extends Thread {
private final Object BLOCKER = new Object();
public Wave() {
super();
setPriority(MAX_PRIORITY);
}
@Override
public void run() {
// I suspect this should be running in an endless loop?
for (;;) {
Wave.high();
long t1 = System.currentTimeMillis();
// Round interval up to the next 20ms "deadline"
LockSupport.parkUntil(BLOCKER, t1 + 20 - (t1 % 20));
Wave.low();
// Round interval up to the next 20ms "deadline"
long t2 = System.currentTimeMillis();
LockSupport.parkUntil(BLOCKER, t2 + 20 - (t2 % 20));
}
}
public static native void high();
public static native void low();
}
由于这取决于ms
中的挂钟时间,而不是更精确的纳秒时间,因此对于更高的频率,这将无法正常工作。但这可能也不起作用,因为GC(和其他进程)可能会在“不幸”的时间内中断此线程,从而导致相同的抖动。
当我在使用JDK 6的Windows 7四核上测试时,我每秒都有一些不可忽略的抖动,所以aix's solution可能更好