10

RXTXを使用してシリアルポートからデータを読み取ります。読み取りは、次の方法で生成されたスレッド内で行われます。

CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(port);
CommPort comm = portIdentifier.open("Whatever", 2000);
SerialPort serial = (SerialPort)comm;
...settings
Thread t = new Thread(new SerialReader(serial.getInputStream()));
t.start();

SerialReaderクラスは、Runnableを実装し、無期限にループし、ポートから読み取り、データを有用なパッケージに構築してから、他のアプリケーションに送信します。しかし、私はそれを次の単純さに減らしました:

public void run() {
  ReadableByteChannel byteChan = Channels.newChannel(in); //in = InputStream passed to SerialReader
  ByteBuffer buffer = ByteBuffer.allocate(100);
  while (true) {
    try {
      byteChan.read(buffer);
    } catch (Exception e) {
      System.out.println(e);
    }
  }
}

ユーザーが停止ボタンをクリックすると、次の機能が起動し、理論的には入力ストリームを閉じて、ブロックしているbyteChan.read(buffer)呼び出しから抜け出します。コードは次のとおりです。

public void stop() {
  t.interrupt();
  serial.close();
}

ただし、このコードを実行すると、ClosedByInterruptExceptionが発生することはありません。これは、入力ストリームが閉じたときに発生する必要があります。さらに、serial.close()の呼び出しで実行がブロックされます。これは、基になる入力ストリームが読み取り呼び出しでブロックされているためです。割り込み呼び出しをbyteChan.close()に置き換えてみましたが、AsynchronousCloseExceptionが発生するはずですが、同じ結果が得られます。

私が欠けているものについての助けをいただければ幸いです。

4

3 に答える 3

9

割り込み可能な I/O をサポートしていないストリームを、InterruptibleChannel単純にラップするだけでは に作成できません (とにかく、ReadableByteChannelを拡張しませんInterruptibleChannel)。

基になる のコントラクトを確認する必要がありますInputStreamSerialPort.getInputStream()その結果の中断可能性について何と言っていますか? 何も言わない場合は、割り込みを無視すると想定する必要があります。

割り込み可能性を明示的にサポートしていない I/O の場合、通常、唯一のオプションは別のスレッドからのストリームを閉じることです。これにより、ストリームへの呼び出しでブロックされたスレッドでIOException(ではないかもしれませんが)がすぐに発生する可能性があります。AsynchronousCloseException

ただし、これでも実装に大きく依存しInputStream、基盤となる OS も要因になる可能性があります。


ReadableByteChannelImplによって返されるクラスのソース コード コメントに注意してくださいnewChannel()

  private static class ReadableByteChannelImpl
    extends AbstractInterruptibleChannel       // Not really interruptible
    implements ReadableByteChannel
  {
    InputStream in;
    ⋮
于 2010-10-01T22:22:38.917 に答える
5

RXTX SerialInputStream (serial.getInputStream() 呼び出しによって返されるもの) は、すべての問題を解決するタイムアウト スキームをサポートしています。新しい SerialReader オブジェクトを作成する前に以下を追加すると、読み取りが無期限にブロックされなくなります。

serial.enableReceiveTimeout(1000);

SerialReader オブジェクト内で、ReadableByteChannel を作成するのではなく、InputStream から直接読み取るようにいくつか変更する必要がありましたが、今では問題なくリーダーを停止して再起動できます。

于 2010-10-13T17:31:43.113 に答える
1

以下のコードを使用して rxtx をシャットダウンしています。それらを起動してシャットダウンするテストを実行しましたが、問題なく動作しているようです。私の読者は次のようになります:

private void addPartsToQueue(final InputStream inputStream) {
    byte[] buffer = new byte[1024];
    int len = -1;
    boolean first = true;
    // the read can throw
    try {
        while ((len = inputStream.read(buffer)) > -1) {
            if (len > 0) {
                if (first) {
                    first = false;
                    t0 = System.currentTimeMillis();
                } else
                    t1 = System.currentTimeMillis();
                final String part = new String(new String(buffer, 0, len));
                queue.add(part);
                //System.out.println(part + " " + (t1 - t0));
            }
            try {
                Thread.sleep(sleep);
            } catch (InterruptedException e) {
                //System.out.println(Thread.currentThread().getName() + " interrupted " + e);
                break;
            }
        }
    } catch (IOException e) {
        System.err.println(Thread.currentThread().getName() + " " + e);
        //if(interruSystem.err.println(e);
        e.printStackTrace();
    }
    //System.out.println(Thread.currentThread().getName() + " is ending.");
}

ありがとう

public void shutdown(final Device device) {
    shutdown(serialReaderThread);
    shutdown(messageAssemblerThread);
    serialPort.close();
    if (device != null)
        device.setSerialPort(null);
}

public static void shutdown(final Thread thread) {
    if (thread != null) {
        //System.out.println("before intterupt() on thread " + thread.getName() + ", it's state is " + thread.getState());
        thread.interrupt();
        //System.out.println("after intterupt() on thread " + thread.getName() + ", it's state is " + thread.getState());
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            System.out.println(Thread.currentThread().getName() + " was interrupted trying to sleep after interrupting" + thread.getName() + " " + e);
        }
        //System.out.println("before join() on thread " + thread.getName() + ", it's state is " + thread.getState());
        try {
            thread.join();
        } catch (InterruptedException e) {
            System.out.println(Thread.currentThread().getName() + " join interruped");
        }
        //System.out.println(Thread.currentThread().getName() + " after join() on thread " + thread.getName() + ", it's state is" + thread.getState());
    }
于 2010-11-30T08:50:24.480 に答える