Contatore server ordinato
L’esempio sopra è un contatore di server ordinato che vogliamo costruire. Quando si fa clic sul pulsante:
- Una richiesta asincrona viene inviato a un server
- Il server incrementa un contatore interno
- Il server restituisce il valore del contatore
- Il client (il nostro sito) visualizza il contatore in un Brindisi sopra indicato.
È importante che l’ordine dei numeri sia conservato al momento della ricezione. Quindi, come possiamo sincronizzare l’ordine delle richieste? Sappiamo che le richieste di rete sono asincrone. È totalmente possibile che la prima richiesta richieda più tempo per arrivare rispetto alla seconda richiesta, o che la seconda richiesta richieda più tempo della terza richiesta e così via. Questo arrivo fuori ordine di richieste sarà un problema per la nostra applicazione.
L’approccio ‘Nessuna sincronizzazione’
Cosa accadrebbe se dovessimo sviluppare questa applicazione senza costrutti di sincronizzazione? Ecco un’implementazione di esempio di una simulazione di questa applicazione senza sincronizzazione.
Il server viene simulato con processCommmand()
e i ritardi di rete vengono simulati con serverDelay()
. Poiché non ci sono meccanismi di sincronizzazione, una volta cliccato il pulsante “Click me”, una nuova richiesta viene immediatamente disattivata.
Questo è il risultato di questa implementazione.
Uh oh — i numeri, come previsto, stanno mostrando out-of-order, e non siamo riusciti a fare la nostra applicazione per mostrare i numeri in ordine.
Superare il problema out-of-order con Mutex
Il problema è che le richieste di rete sono fuori servizio, ma la nostra applicazione vuole che siano in ordine. Un modo per risolvere questo problema è utilizzare un blocco Mutex per consentire l’elaborazione di una sola richiesta alla volta, bloccando le altre richieste finché non è il loro turno.
Ecco l’implementazione con Mutex.
Il flusso di utilizzo dell’API Mutex è il seguente:
- Riga 23: Viene avviata una richiesta di acquisizione di
clientLock
. Questa richiesta verrà bloccata se qualcun altro ha già acquisito il blocco e non lo ha ancora rilasciato - Riga 33: Il blocco del client viene rilasciato dopo che il server ha risposto e abbiamo mostrato il toast. Ciò consente ad altri eventi di clic del pulsante di competere per il blocco e avviare la richiesta di rete del server!
Questo meccanismo di blocco garantisce che un solo evento pulsante verrà elaborato alla volta, bloccando e accodando gli altri. Ora abbiamo raggiunto l’implementazione ordinata prevista del nostro esempio originale mostrato all’inizio!
Limitare il numero di Toast visibili
Cosa succede se non ti piace che diversi Toast possano inondare lo schermo alla volta? Possiamo estendere la nostra logica per limitare il numero di Toast visualizzati alla volta. Il nostro costrutto di sincronizzazione qui sarebbe un semaforo!
Pensa a un Sempahore come un Mutex, ma può consentire a più richieste asincrone di eseguire un pezzo di codice alla volta. È possibile configurare il numero massimo, anche!
Usando un Mutex e un semaforo, sono stato in grado di limitare il numero di Toast sullo schermo a 2 alla volta.
Ed ecco il codice associato all’esempio sopra
Riga 6
La struttura Sempahore viene inizializzata con il valore 2, che specifica che è possibile visualizzare solo un massimo di 2 toast per volta.
Linea 26-31
La nostra logica semaforo viene ad aiutarci quando vogliamo visualizzare il Brindisi. Cerchiamo di acquisire il Sempahore. Se ci sono riusciti, creiamo l’oggetto Toast e quindi passiamo releaseSemaphore()
alla funzione completeCallback
del Toast. Questo callback viene chiamato quando il toast viene respinto.