Bestellter Serverzähler
Das obige Beispiel ist ein geordneter Serverzähler, den wir erstellen möchten. Wenn Sie auf die Schaltfläche klicken:
- Eine asynchrone Anforderung wird an einen Server gesendet
- Der Server erhöht einen internen Zähler
- Der Server gibt den aktuellen Zählerwert zurück
- Der Client (unsere Webseite) zeigt den Zähler in einem oben gezeigten Toast an.
Es ist wichtig, dass die Reihenfolge der Nummern beim Empfang erhalten bleibt. Wie können wir also die Reihenfolge der Anfragen synchronisieren? Wir wissen, dass Netzwerkanforderungen asynchron sind. Es ist durchaus möglich, dass die erste Anforderung länger dauert als die zweite Anforderung oder dass die zweite Anforderung länger dauert als die dritte Anforderung usw. Diese Out-of-Order-Ankunft von Anfragen wird ein Problem für unsere Anwendung sein.
Der Ansatz ‚Keine Synchronisation‘
Was würde passieren, wenn wir diese Anwendung ohne Synchronisationskonstrukte entwickeln würden? Hier ist eine Beispielimplementierung einer Simulation dieser Anwendung ohne Synchronisation.
Der Server wird mit processCommmand()
und die Netzwerkverzögerungen mit serverDelay()
simuliert. Da es keine Synchronisationsmechanismen gibt, wird nach dem Klicken auf die Schaltfläche „Click me“ sofort eine neue Anforderung ausgelöst.
Dies ist das Ergebnis dieser Implementierung.
Uh oh – die Zahlen, wie erwartet, zeigen out-of-order, und wir haben es versäumt, unsere Anwendung zu machen Zahlen, um zu zeigen.
Überwindung des Out-of-Order-Problems mit Mutex
Das Problem ist, dass Netzwerkanforderungen nicht in Ordnung sind, aber unsere Anwendung möchte, dass sie in Ordnung sind. Eine Möglichkeit, dies zu lösen, besteht darin, eine Mutex-Sperre zu verwenden, um jeweils nur eine Anforderung zu verarbeiten und die anderen Anforderungen zu blockieren, bis sie an der Reihe sind.
Hier ist die Implementierung mit Mutex.
Der Mutex-API-Nutzungsfluss ist der folgende:
- Zeile 23: Eine Anforderung zum Erwerb der
clientLock
wird initiiert. Diese Anforderung wird blockiert, wenn jemand anderes die Sperre bereits erworben und noch nicht freigegeben hat - Zeile 33: Die Clientsperre wird freigegeben, nachdem der Server geantwortet hat und wir den Toast angezeigt haben. Auf diese Weise können andere Tastenklickereignisse jetzt um die Sperre konkurrieren und ihre Servernetzwerkanforderung initiieren!
Dieser Verriegelungsmechanismus garantiert, dass jeweils nur ein Tastenereignis verarbeitet wird, wodurch die anderen blockiert und in die Warteschlange gestellt werden. Wir haben nun die beabsichtigte geordnete Umsetzung unseres eingangs gezeigten Originalbeispiels erreicht!
Anzahl der sichtbaren Toasts begrenzen
Was ist, wenn Sie nicht möchten, dass mehrere Toasts gleichzeitig den Bildschirm überfluten können? Wir können unsere Logik erweitern, um die Anzahl der gleichzeitig angezeigten Toasts zu begrenzen. Unser Synchronisationskonstrukt wäre hier ein Semaphor!
Stellen Sie sich einen Sempahore wie einen Mutex vor, aber es können mehrere asynchrone Anforderungen gleichzeitig einen Code ausführen. Sie können auch die maximale Anzahl konfigurieren!
Mit einem Mutex und einem Semaphor konnte ich die Anzahl der Toasts auf dem Bildschirm auf jeweils 2 begrenzen.
Und hier ist der Code, der dem obigen Beispiel zugeordnet ist
Zeile 6
Die Sempahore-Struktur wird mit dem Wert 2 initialisiert, der angibt, dass nur maximal 2 Toasts gleichzeitig angezeigt werden können.
Zeile 26-31
Unsere Semaphor-Logik hilft uns, wenn wir den Toast anzeigen möchten. Wir versuchen, den Sempahore zu erwerben. Wenn es uns gelungen ist, erstellen wir das Toast-Objekt und übergeben dann releaseSemaphore()
an die completeCallback
-Funktion des Toasts. Dieser Callback wird aufgerufen, wenn der Toast beendet wird.