2010-10-04 12 views
11

Mi problema: Tengo la red inalámbrica 802.15.4 conectada a un puerto serie (usando un contenedor). Puedo enviar paquetes a la red y escuchar si hay paquetes entrantes. Como se puede imaginar, esto es altamente asincrónico.La mejor manera de sincronizar una tarea asíncrona

Aquí viene la tarea: quiero enviar comandos a la red y esperar la respuesta en una llamada de función. Por ejemplo: Quiero conseguir la temperatura del nodo con el ID de red 1338.

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

¿Hay una mejor manera de esperar a que un mensaje de respuesta distinta de hacer todo esto "sincronizado (objeto) esperar (..) notificar (...) "cosas?

Saludos, bigbohne

Tal vez para añadir algo de sabor:

Esto debe terminar todo en una interfaz web donde el usuario puede solicitar estos comandos (ya sea a través de Ajax o directamente). También he pensado en almacenar en caché los valores de respuesta en una base de datos. Pero para algunos comandos, MUSS tiene una respuesta directa de éxito/falla

+0

OK. Esta pregunta apunta más en la dirección de "¿hay algún truco genial de Java para resolver este problema?" – Bigbohne

+0

Este también es fresco –

Respuesta

7

Usted puede hacer esto con un BlockingQueue por lo que no tendrá que gestionar manualmente cualquiera de la sincronización. La solicitud puede enviar el mensaje, luego llamar a take() en un BlockingQueue que esperará a que un elemento esté presente. El elemento es la respuesta que se inserta en la cola por el oyente que tenga en el puerto cuando se devuelva la respuesta.

Sólo hay que coordinar para que el oyente y el solicitante comparten la misma cola. Solo necesita una cola de tamaño uno para cada solicitud para admitir este escenario.

// 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()); 
+0

¡Eso es exactamente el "Special Java Thingy" que estaba buscando! – Bigbohne

1

La mejor manera es finalizarlo en alguna clase de solicitud/respuesta reutilizable. De esta forma, puede tener una forma estándar de consultar el puerto serie y esperar una respuesta. Sin embargo, esta clase sin duda tendrá que usar la palabra clave sincronizada y esperar y notificar los comandos en algún lugar de su implementación. Esta es una parte clave de la escritura de Java y es importante entender cómo funcionan.

Si tuviera que diseñar una función como usted dice, debe asegurarse de llamarla desde un hilo que puede bloquear la espera del resultado. La función tendrá que implementar algún tipo de bucle de espera dentro de ella esperando la respuesta del puerto serie. Por lo tanto, es importante que el hilo en el que se está ejecutando pueda esperar también.

Esto también trae un punto adicional. Si tiene varios hilos haciendo esto, necesitará tener alguna clase que maneje la comunicación del puerto serie que pueda tratar múltiples solicitudes provenientes de múltiples hilos y ponerlos en cola según sea necesario para manejar la naturaleza asíncrona del puerto serial y el dispositivo específico a lo que te estás conectando Por ejemplo, puede que no sea apropiado enviar un segundo comando antes de que la respuesta del primero se lea completamente.

Aquí hay varios problemas complicados, y es importante contar con un buen diseño que los aborde de manera razonable.

+0

Gracias por su entrada. Esto me lleva de vuelta a la pluma y el papel :) – Bigbohne

2

No estoy seguro de entender la pregunta correctamente, pero suelo usar un Future<T> para este tipo de tareas.

Internamente, la implementación Future<T> utiliza esperar y notificar y todo eso, pero la interfaz se vuelve bastante limpia.

Future<Double> getTemperature(int id); 

En su código de comunicación puede asignar los mensajes entrantes hacia futuros no realizados. Si se garantiza pedido que podría hacer algo como

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. 
    } 
} 

Dónde MyFutureImpl es una futura implementación muy básica. Supongo que hay un hilo de comunicaciones que llama al response() cuando se recibe un paquete.También estoy suponiendo que el serializeAndSend() -función se encarga de la escritura para el cliente o se bloquea hasta que la operación de escritura se puede hacer o pasarse a un hilo de comunicación.

El uso del mapa y de la cola estructuras de concurrencia con capacidad podría hacer algo de synchronization s innecesario. Si solo hay una llamada pendiente por identificación, la cola se vuelve innecesaria por supuesto.

+0

Gracias por tu idea. tendrá que recorrer su código – Bigbohne

Cuestiones relacionadas