Contador de Servidor Ordenado
El ejemplo anterior es un contador de servidor ordenado que queremos construir. Al hacer clic en el botón:
- Se envía una solicitud asíncrona a un servidor
- El servidor incrementa un contador interno
- El servidor devuelve el valor del contador actual
- El cliente (nuestra página web) muestra el contador en un brindis que se muestra arriba.
Es importante que el orden de los números se conserve cuando se reciban. Entonces, ¿cómo podemos sincronizar el orden de las solicitudes? Sabemos que las solicitudes de red son asíncronas. Es totalmente posible que la primera solicitud tarde más en llegar que la segunda, o que la segunda solicitud tarde más que la tercera, y así sucesivamente. Esta llegada fuera de servicio de las solicitudes será un problema para nuestra aplicación.
El enfoque «Sin sincronización»
¿Qué pasaría si desarrolláramos esta aplicación sin construcciones de sincronización? A continuación se muestra una implementación de ejemplo de una simulación de esta aplicación sin sincronización.
El servidor se simula con processCommmand()
, y los retrasos de red se simulan con serverDelay()
. Dado que no hay mecanismos de sincronización, una vez que se hace clic en el botón «Haga clic en mí», se dispara una nueva solicitud de inmediato.
Este es el resultado de esta implementación.
Uh oh — los números, como se esperaba, se muestran fuera de la orden, y no hemos podido hacer nuestra aplicación para mostrar los números en orden.
Superar el problema de falta de orden con Mutex
El problema es que las solicitudes de red están fuera de orden, pero nuestra aplicación quiere que estén en orden. Una forma de resolver esto es usar un bloqueo Mutex para permitir que solo se procese una solicitud a la vez, bloqueando las otras solicitudes hasta que sea su turno.
Aquí está la implementación con Mutex.
El flujo de uso de la API de Mutex es el siguiente:
- Línea 23: Se inicia una solicitud para adquirir el
clientLock
. Esta solicitud se bloqueará si alguien más ya ha adquirido el bloqueo y aún no lo ha liberado - Línea 33: El bloqueo del cliente se libera después de que el servidor haya respondido y hayamos mostrado el brindis. ¡Esto permite que otros eventos de clic de botón compitan por el bloqueo e inicien su solicitud de red de servidor!
Este mecanismo de bloqueo garantiza que solo se procesará un evento de botón a la vez, bloqueando y haciendo cola a los demás. ¡Ahora hemos logrado la implementación ordenada prevista de nuestro ejemplo original que se muestra al principio!
Limitar el número de Brindis visibles
¿Qué pasa si no te gusta que varios Brindis puedan inundar la pantalla a la vez? Podemos extender nuestra lógica para limitar el número de Brindis mostrados a la vez. ¡Nuestra construcción de sincronización aquí sería un Semáforo!
Piense en un Sempahore como un Mutex, pero puede permitir que múltiples solicitudes asíncronas ejecuten un fragmento de código a la vez. ¡También puede configurar el número máximo!
Usando un Mutex y un Semáforo, pude limitar el número de Brindis en la pantalla a 2 a la vez.
Y aquí está el código asociado con el ejemplo anterior
Línea 6
La estructura Sempahore se inicializa con el valor 2, que especifica que solo se pueden mostrar un máximo de 2 tostadas a la vez.
Línea 26-31
Nuestra lógica de semáforos viene a ayudarnos cuando queremos mostrar el Brindis. Intentamos adquirir el Sempahore. Si tuvimos éxito, entonces creamos el objeto Toast, y luego pasamos releaseSemaphore()
a la función completeCallback
del Toast. Esta devolución de llamada se llama cuando se desestima el brindis.