3

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();
}

ここで、high()とlow()はJNIを使​​用して実装されます(共有Cライブラリがパラレルポートを制御します)。それはかなりうまく機能します。周期が約40msの方形波を発生します。オシロスコープを使用すると、コンピュータがアイドル状態のときの標準偏差は約10マイクロ秒のように見えます。コンピューターがアイドル状態でない場合、標準偏差ははるかに大きくなります。これは、より多くのコンテキストスイッチが発生し、スレッドが待機状態で長く留まりすぎて、指定された20ミリ秒が正確に達成されないためだと思います。

私の実装をより正確にする方法はありますか?これにはハードウェアを使用できることはわかっていますが、ソフトウェアでもこれを実行できるかどうかを知りたいです。

時計を「聞いて」、ミリ秒のタイミングでアクションを実行するという選択肢はありますか?

4

3 に答える 3

1

クロックを「聞く」だけでは、ジッターを引き起こすコンテキスト スイッチの問題は解決されません。

これにコアを捧げることができる場合:

このようにして、非常に低いジッターを達成できるはずです。

もちろん、タスクが単純に方形波を生成することである場合、これはコンピューティング リソースのかなり非効率的な使用です。

于 2012-05-03T12:23:33.110 に答える
1

ジッターには 2 つの原因があると思います。

まず、Java でのガベージ コレクション (および場合によっては JIT などの他のバックグラウンド プロセス)。あなたが与えたコードについては、gc があってはなりません。ただし、これが大規模なシステムの一部である場合は、ガベージ コレクションが必要であり、実行時のタイミングが変わる可能性があることに気付くでしょう。jvm設定(java -X)をいじって、これを改善してみてください。

2 つ目は、システム スケジューラです。aix による提案に加えて、プロセスの優先順位を上げたり、Linux 固有の微調整を行ったりすることができます。 この記事では、Linux に関するいくつかの問題について説明します。 ubuntuには低レイテンシーのカーネルがあり、インストールできますが、実際に含まれているものに関する情報が見つからないため、他のシステムでも同じことができます(更新:このパッチが含まれている可能性があると思います)。より多くの情報を探したい場合は、「低遅延」が検索の鍵であり、Linux でオーディオ処理を行っている人は、これを最も気にする傾向があります)。

于 2012-05-03T13:08:58.690 に答える
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 のソリューションの方がおそらく優れています。

于 2012-05-03T12:32:47.957 に答える