So erstellen Sie ein Semaphor in bash

Inhalt

Bash-Shell

Entwickeln Sie eine Multithread-Anwendung?? Früher oder später, du wirst wahrscheinlich eine Ampel benutzen müssen. In diesem Artikel, Du wirst lernen was eine Ampel ist, wie erstelle ich / übe eins in bash und mehr.

Was ist ein Ampeln?

Ein Semaphor ist ein Programmierkonstrukt, das in Computerprogrammen verwendet wird, die mehrere Verarbeitungs-Threads verwenden. (Computer, die Threads verarbeiten, die Quellcode aus demselben Programm oder einer Reihe von Programmen ausführen) die ausschließliche Nutzung einer gemeinsamen Ressource zu einem bestimmten Zeitpunkt zu erreichen. . Viel einfacher gesagt, stell dir das vor als “eins gleichzeitig, bitte”.

Eine Ampel wurde erstmals Ende der 1990er Jahre definiert. 1960 von dem verstorbenen Informatiker Edsger Dijkstra aus Rotterdam in den Niederlanden. Sie haben wahrscheinlich in Ihrem Leben häufig Ampeln benutzt, ohne es ausdrücklich zu merken!!

Bleiben Sie eine Weile in den Niederlanden, ein Land voller kleiner Wasserstraßen und vieler beweglicher Brücken (namens Zugbrücke in amerikanischem englisch), Sie können viele tolle Beispiele aus der realen Welt einer Ampel sehen; Betrachten Sie den Griff eines Zugbrücken-Operators: rauf oder runter. Dieser Griff ist die Ampelvariable, die die Wasserstraße oder Autobahn vor Unfällen schützt. A) Ja, Wasserstraße und Straßen könnten als weitere Variablen angesehen werden, die durch die Ampel geschützt sind.

Wenn der Griff oben und die Brücke geöffnet ist, die ausschließliche Nutzung des Kreuzungswassers / Straße wird dem Schiff oder den Schiffen gegeben, die durch den Wasserkanal fahren. Wenn der Griff unten ist, die Brücke ist gesperrt und die ausschließliche Nutzung des Kreuzungswassers ist gegeben / Straße zu den Autos, die über die Brücke fahren.

Die Semaphor-Variable kann den Zugriff auf einen anderen Satz von Variablen steuern. Als Beispiel, der Zustand des Griffs verhindert das $cars_per_minute und $car_toll_booth_total_income Variablen, damit sie nicht aktualisiert werden, etc.

Wir können das Beispiel noch etwas weiterführen und erklären, wenn der Griff nach oben oder unten funktioniert, sowohl Kapitäne von Booten im Wasser als auch Menschen, die Autos und Lastwagen auf der Straße fahren, können ein passendes Licht sehen: alle Operatoren können eine gemeinsame Variable für einen bestimmten Zustand lesen.

Auch wenn das hier beschriebene Szenario nicht nur eine Ampel ist, aber gleichzeitig ist es ein einfacher Mutex. Ein Mutex ist ein weiteres gängiges Programmierkonstrukt, das einem Semaphor sehr ähnlich ist, mit der zusätzlichen Bedingung, dass ein Mutex nur von demselben Task oder Thread entsperrt werden kann, der ihn gesperrt hat. Mutex significa “sich gegenseitig ausschließen”.

Für diesen Fall, das trifft auf unser beispiel zu, da der Brückenbetreiber der einzige ist, der die Kontrolle über unseren Semaphor und Mutex up hat / Nieder. Umgekehrt, wenn das Wachhaus am Ende der Brücke einen Brückenüberbrückungsschalter hätte, wir hätten immer noch eine Semaphor-Konfiguration, aber kein mutex.

Beide Konstrukte werden regelmäßig in der Computerprogrammierung verwendet, wenn mehrere Threads verwendet werden, um sicherzustellen, dass immer nur eine einzelne Prozedur oder Aufgabe auf eine bestimmte Ressource zugreift. Einige Ampeln können ultraschnell schalten, als Beispiel, bei Verwendung in Multithread-Finanzmarkthandelssoftware, und manche können viel langsamer sein, sie ändern ihren Zustand nur alle paar Minuten, B. beim Einsatz auf einer automatisierten Zugbrücke oder an einem Bahnübergang.

Jetzt haben wir ein besseres Verständnis von Ampeln, lass uns einen in bash implementieren.

Implementieren Sie eine Ampel in Bash: Es ist einfach auf dem?

Die Implementierung eines Semaphors in Bash ist so einfach, dass es sogar direkt über die Befehlszeile erfolgen kann, So scheint es zumindest …

Comencemos de forma simple.

BRIDGE=up
if [ "${BRÜCKE}" = "herab" ]; dann echo "Autos können passieren!"; sonst Echo "Schiffe können passieren!"; fi
BRIDGE=down
if [ "${BRÜCKE}" = "herab" ]; dann echo "Autos können passieren!"; sonst Echo "Schiffe können passieren!"; Sein

Beispiel für Update-Befehlszeile und Ausgabe des Bridge-Status

In diesem Code, Die Variable BRIDGE hat unseren Brückenstatus. Wenn wir es einlegen up, Schiffe können passieren und wenn wir es einlegen down, Autos können passieren. Al mismo tiempo podríamos leer el valor de nuestra variable en cualquier punto para ver si el puente está verdaderamente hacia arriba o hacia abajo. Das Teilen / gemeinsames, unter diesen Umständen, ist unsere Brücke.

dennoch, dieses Beispiel ist einfädig und, das liegt daran, wir finden nie wiehilf den Gewerkschaften Situation. Eine andere Möglichkeit, darüber nachzudenken, ist, dass unsere Variable niemals sein kann up und down genau zeitgleich mit der sequentiellen Ausführung des Codes, mit anderen Worten, Schritt für Schritt.

Zu beachten ist auch, dass wir den Zugriff auf eine andere Variable nicht wirklich kontrollieren (wie eine Ampel regelmäßig), so unser BRIDGE Variable ist nicht wirklich eine echte Semaphor-Variable, auch wenn es näher kommt.

Zusammenfassend, sobald wir verschiedene Threads vorstellen, die sich auf die BRIDGE variabel stoßen wir auf Probleme. Als Beispiel, was ist, wenn, direkt danach BRIDGE=up Befehl, noch ein thread probleme BRIDGE=down was später zu der Nachricht führen würde Cars may pass! Ausgang, obwohl der erste Thread erwartet hätte, dass die Brücke ist up, und eigentlich bewegt sich die brücke noch. Gefährlich!

Man sieht, wie schnell die Dinge trüb und unübersichtlich werden können, ganz zu schweigen von komplex, wenn mit genügend Threads gearbeitet wird.

Die Situation, in der mehrere Threads versuchen, dieselbe Variable gleichzeitig zu aktualisieren oder zumindest rechtzeitig genug, damit ein anderer Thread die Situation durcheinander bringt (was bei Zugbrücken sehr lange dauern kann) es wird genannt Rennbedingung: zwei Threads, die konkurrieren, um eine Variable oder einen Status zu aktualisieren oder zu melden, mit der Folge, dass ein oder mehrere Threads ganz schief gehen können.

Wir können diesen Code stark verbessern, indem wir den Code in Prozeduren fließen lassen und eine echte Semaphor-Variable verwenden, die den Zugriff auf unsere beschränkt BRIDGE variabel je nach Situation.

Erstellen eines Bash-Semaphors

Implementieren Sie ein vollständiges Multithread, mach es threadsicher (eine Computerdefinition, um Software zu beschreiben, die threadsicher ist oder so entwickelt wurde, dass sich Threads nicht negativ oder falsch beeinflussen können, wenn sie es nicht sollten) Es ist keine leichte Aufgabe. Selbst ein gut geschriebenes Programm, das Semaphoren verwendet, ist nicht garantiert, dass es absolut Thread-sicher ist..

Je mehr Threads es gibt, und je höher die Häufigkeit und Komplexität der Interaktionen zwischen den Threads, Rennbedingungen sind wahrscheinlicher.

Für unser kleines Beispiel, Wir werden die Definition eines Bash-Semaphors sehen, wenn einer der Zugbrückenoperatoren den Brückengriff senkt, zeigt an, dass Sie die Brücke absenken möchten. Los lectores ávidos pueden haber notado la referencia a OperatorS Anstatt von Operator: ahora hay varios operadores que pueden bajar el puente. Mit anderen Worten, hay varios subprocesos o tareas que se ejecutan al mismo tiempo.

#!/bin/bash

BRIDGE_SEMAPHORE=0

lower_bridge(){  # Ein Bediener setzt einen der Griffe der Brückenbedienung nach unten (als neuer Staat).
  # Nehmen wir an, es wurde zuvor zwischen den Betreibern vereinbart, dass, sobald einer der Betreiber 
  # Verschiebt ein Bridge-Vorgangshandle, dass ihr Befehl ausgeführt werden muss, entweder früher oder später
  # daher, we commence a loop which will wait for the bridge to become available for movement
  while true; do
    if [ "${BRIDGE_SEMAPHORE}" -Eq 1 ]; then
      echo "Brückensemaphor verriegelt, Verschieben der Brücke oder anderes Problem. Warten 2 Minuten vor der erneuten Überprüfung."
      Schlaf 120
      fortsetzen  # Continue loop
    elif [ "${BRIDGE_SEMAPHORE}" -Eq 0 ]; then   
      echo "Befehl "Untere Brücke" akzeptiert, Verriegelung des Semaphors und Absenken der Brücke."
      BRIDGE_SEMAPHORE=1
      execute_lower_bridge
      wait_for_bridge_to_come_down
      BRIDGE='down'
      echo "Brücke abgesenkt, sicherzustellen, dass mindestens 5 Minuten vergehen, bevor die nächste erlaubte Brückenbewegung vorliegt."
      Schlaf 300
      Echo "5 Verstrichenes Protokoll, Entsperren von Semaphor (Freigeben der Brückensteuerung)"
      BRIDGE_SEMAPHORE=0
      break  # Exit loop
    fi
  done
}

Una implementación de semáforo en Bash

Aquí tenemos un lower_bridge función que hará una serie de cosas. Zuerst, Angenommen, ein anderer Betreiber hat kürzlich die Brücke in letzter Minute verlegt. Als solche, Es gibt einen anderen Thread, der Code in einer Funktion ähnlich diesem Aufruf ausführt raise_bridge.

Genau genommen, diese Funktion hat das Anheben der Brücke beendet, hat aber eine obligatorische Wartezeit von eingeführt 5 Minuten, die alle Betreiber im Voraus vereinbart haben und die im Quellcode kodiert wurden: Damit die Brücke nicht hochgeht / komm die ganze zeit runter. Gleichzeitig sieht man diese obligatorische Wartezeit von 5 Minuten in dieser Funktion implementiert als sleep 300.

Dann, wenn das raise_bridge die Funktion ist in Betrieb, wird die Semaphor-Variable gesetzt haben BRIDGE_SEMAPHORE ein 1, genauso machen wir es im Code hier (direkt danach echo "Lower bridge command accepted, locking semaphore and lowering bridge" Befehl), und – durch die erste if Bedingte Prüfung in diesem Code: die in dieser Funktion vorhandene Endlosschleife wird fortgesetzt (ref continue Im Code) schleifen, mit Pausen von 2 Protokoll, Als die BRIDGE_SEMAPHORE variabel ist 1.

Sobald das raise_bridge Die Show beendet das Anheben der Brücke und beendet ihre fünfminütige Aussetzung, wird die gründen BRIDGE_SEMAPHORE ein 0, erlauben unsere lower_bridge co-Funktion beginnt mit der Ausführung von Funktionen execute_lower_bridge und anschließend wait_for_bridge_to_come_down gleichzeitig haben wir unsere Ampel wieder gesperrt um 1 um zu verhindern, dass andere Funktionen die Brücke übernehmen.

dennoch, es gibt Mängel in diesem Code und mögliche Race-Conditions, die weitreichende Konsequenzen für Brückenbetreiber haben können. Kannst du welche sehen??

das "Lower bridge command accepted, locking semaphore and lowering bridge" nicht fadensicher.

Wenn ein anderer Thread, als Beispiel raise_bridge läuft gleichzeitig und versucht, auf die BRIDGE_SEMAPHORE Variable, könnte sein (Wenn BRIDGE_SEMAPHORE=0 und beide laufenden Threads erreichen ihre jeweiligen echoGenau zur gleichen Zeit sehen die Brückenbetreiber “Der Befehl "Bottom Bridge" wird akzeptiert, die Ampel ist blockiert und die Brücke wird abgesenkt” und “Brückenhubbefehl akzeptiert, die Ampel ist blockiert und die Brücke wird angehoben”. Direkt hintereinander auf dem Bildschirm! Besorgt, Nein?

Noch beängstigender ist die Tatsache, dass beide Threads weitergeführt werden können BRIDGE_SEMAPHORE=1, Und beide Threads können weiterlaufen! (Es gibt nichts, was sie davon abhält, es zu tun) Der Grund ist, dass es für solche Szenarien noch nicht viel Schutz gibt. Obwohl dieser Code ein Semaphor implementiert, es ist keineswegs threadsicher. Wie gesagt, Multithread-Codierung ist komplex und erfordert viel Erfahrung.

Auch wenn der Zeitaufwand unter diesen Umständen minimal ist (1-2 Die Ausführung von Codezeilen dauert nur wenige Millisekunden), und angesichts der wahrscheinlich geringen Anzahl von Brückenbetreibern, die Wahrscheinlichkeit dafür ist sehr gering. dennoch, die Tatsache, dass es lebensfähig ist, macht es gefährlich. Thread-sicheren Code in Bash zu erstellen ist keine leichte Aufgabe.

Das könnte noch verbessert werden, als Beispiel, Einführung einer Vorverriegelung und / oder eine Art Verzögerung bei einer erneuten Nachprüfung einführen (auch wenn dies wahrscheinlich eine zusätzliche Variable erfordert) oder regelmäßige Nachkontrolle vor der eigentlichen Ausführung der Brücke. , etc. Eine andere Alternative besteht darin, eine Prioritätswarteschlange oder eine Zählervariable zu erstellen, die überprüft, wie viele Threads die Steuerung der Brücke blockiert haben, etc.

Ein weiterer häufig verwendeter Ansatz, als Beispiel, beim Ausführen mehrerer Bash-Skripte, die möglicherweise interagieren, ist zu verwenden mkdir Ö flock als Basis-Lock-Operationen. Es gibt mehrere Beispiele für deren Umsetzung online verfügbar, als Beispiel, Welche Unix-Befehle können als Semaphor verwendet werden? / Blockierung?.

Ende

In diesem Artikel, Wir schauen uns an, was eine Ampel ist. Gleichzeitig berührten wir kurz das Thema eines Mutex. Zusammenfassend, analysieren wir die Implementierung eines Semaphors in Bash am praktischen Beispiel mehrerer Brückenbetreiber, die eine mobile Brücke betreiben / Zugbrücke. Gleichzeitig erforschen wir, wie komplex die Umsetzung einer zuverlässigen Lösung auf Ampelbasis ist.

Wenn Ihnen das Lesen dieses Artikels gefallen hat, werfen Sie einen Blick auf unsere Ansprüche, Fehler und Abstürze: Was ist der Unterschied? Artikel.

Abonniere unseren Newsletter

Wir senden Ihnen keine SPAM-Mail. Wir hassen es genauso wie du.