12

私の問題:802.15.4ワイヤレスネットワークをシリアルポートに接続しています(ラッパーを使用)。パッケージをネットワークに送信して、着信パッケージをリッスンできます。ご想像のとおり、これは非常に非同期です。

ここにタスクがあります。ネットワークにコマンドを送信し、1回の関数呼び出しで応答を待ちます。例:ネットワークID1338のノードから温度を取得したい。

double getTemperature(int id) throws Exception { .... }

この「synchonized(object)wait(..)notify(..)」のすべてを実行する以外に、応答メッセージを待機するためのより良い方法はありますか?

よろしく、bigbohne

多分いくつかのスパイスを追加する:

これはすべて、ユーザーがこれらのコマンドを(ajaxを介してまたは直接)要求できるWebインターフェースで終了する必要があります。また、応答値をデータベースにキャッシュすることも考えました。しかし、いくつかのコマンドについては、MUSSは成功/失敗の直接的な答えを持っています

4

3 に答える 3

7

これはBlockingQueueを使用して実行できるため、同期を手動で管理する必要はありません。リクエストはメッセージを送信してから、BlockingQueueでtake()を呼び出し、要素が存在するのを待ちます。要素は、応答が返されるときにポート上にあるリスナーによってキューに挿入される応答です。

リスナーとリクエスターが同じキューを共有するように調整する必要があります。このシナリオをサポートするには、リクエストごとにサイズ1のキューのみが必要です。

// Send method
BlockingQueue<Reply> q = new ArrayBlockingQueue<Reply>(1);
serialCom.registerQueue(myRequest.getId());
serialCom.sendRequest(myRequest);
return q.take();

//Listener
BlockingQueue<Reply> q = queueMap.get(incomingMessage.getId());
q.add(incomingMessage.getReply());
于 2010-10-04T16:55:35.603 に答える
2

質問を正しく理解できるかどうかはわかりませんが、私は通常、Future<T>この種のタスクにを使用します。

内部的には、Future<T>実装は待機と通知などを使用しますが、インターフェース自体はかなりクリーンになります。

Future<Double> getTemperature(int id);

次に、通信コードで、着信メッセージを満たされていない未来に向けてマッピングできます。注文が保証されている場合は、次のようなことができます

class Something {
    Map<Integer, Queue<Object>> requests;

    synchronized Future<?> request(int id, Object data) {
        MyFutureImpl future = new MyFuture();
        requests.get(id).add(future);
        serializeAndSend(id, data);
        return future;
    }

    void serializeAndSend(id, data) {...}

    synchronized void response(int id, Object data) {
        MyFutureImpl future = requests.get(id).remove();
        future.setValue(data); // This would fulfill the future, and any
                               // threads waiting in a get() will get the
                               // value and continue.
    }
}

MyFutureImplは、非常に基本的な将来の実装です。response()パケットを受信したときに呼び出す通信スレッドがあると思います。また、serializeAndSend()-functionは、書き込み操作が行われるか、通信スレッドに渡されるまで、クライアントまたはブロックへの書き込みを処理すると想定しています。

同時実行可能なマップおよびキュー構造を使用すると、一部synchronizationが不要になる可能性があります。IDごとに未処理の呼び出しが1つしかない場合は、もちろんキューは不要になります。

于 2010-10-04T13:35:05.917 に答える
1

より良い方法は、再利用可能な要求/応答クラスでラップすることです。このようにして、シリアルポートを照会し、応答を待つ標準的な方法を使用できます。ただし、このクラスは間違いなく、synchronizedキーワードを使用し、実装のどこかでコマンドを待機して通知する必要があります。これはJavaを作成する上で重要な部分であり、Javaがどのように機能するかを理解することが重要です。

あなたが言うような関数を設計する場合は、結果の待機をブロックできるスレッドから関数を呼び出すようにする必要があります。関数は、シリアルポートからの応答を待機する、ある種の待機ループを内部に実装する必要があります。したがって、実行中のスレッドが何であれ、同様に待機できることが重要です。

これにより、さらに1つのポイントが発生します。これを行う複数のスレッドがある場合は、シリアルポートと特定のデバイスの非同期性を処理するために、複数のスレッドからの複数の要求を処理し、必要に応じてそれらをキューに入れることができるシリアルポート通信を処理するクラスが必要になります接続している接続先。たとえば、最初のコマンドからの応答が完全に読み取られる前に2番目のコマンドを送信することは適切でない場合があります。

ここにはいくつかの複雑な問題があり、それらすべてに合理的な方法で対処する適切な設計を用意することが重要です。

于 2010-10-04T13:03:35.517 に答える