Dekker-Algorithmus

aus Wikipedia, der freien Enzyklopädie
Dies ist eine alte Version dieser Seite, zuletzt bearbeitet am 14. August 2016 um 13:43 Uhr durch Evotopid (Diskussion | Beiträge) ("Belege fehlen" Baustein eingefügt.). Sie kann sich erheblich von der aktuellen Version unterscheiden.
Zur Navigation springen Zur Suche springen

Der Dekker-Algorithmus (nach Theodorus Dekker) ist wie der Peterson-Algorithmus eine vollständige Lösung des Problems, den wechselseitigen Ausschluss (Mutex) in der dezentralen Steuerung von Prozessen (Prozesssynchronisation) zu gewährleisten. Er vermeidet gegenseitiges Blockieren (Deadlock) und gewährleistet, dass stets genau ein Prozess in einen kritischen Abschnitt gelangen kann (Sequentialisierung).

Schema

Der Algorithmus kann mit folgendem C-Code schematisch beschrieben werden:

  // globale Variablendeklaration
  boolean flag0 = false;
  boolean flag1 = false;
  int turn = 0;   // alternativ: turn = 1
  // Prozess 0
  p0: flag0 = true;
      while (flag1) {
          if (turn != 0) {
              flag0 = false;
              while (turn != 0) {
              }
              flag0 = true;
           }
      }

      // kritischer Abschnitt
      turn = 1;
      flag0 = false;
// Prozess 1
p1: flag1 = true;
    while (flag0) {
        if (turn != 1) {
            flag1 = false;
            while (turn != 1) {
            }
            flag1 = true;
        }
    }

    // kritischer Abschnitt
    turn = 0;
    flag1 = false;

Funktionsweise

Der Dekker-Algorithmus für 2 Prozesse arbeitet mit 3 Variablen: 2 Flags und einer Variable turn. Für jeden Prozess existiert genau ein Flag. Ein gesetztes Flag (flag=true) signalisiert, dass sich der dazugehörige Prozess im kritischen Abschnitt befinden könnte, die Variable turn fungiert als eine Art Token.

Die Eintrittsbedingung für die Schleife ist das Flag des anderen Prozesses: Ist dieses gesetzt, befindet sich der andere Prozess entweder im kritischen Bereich oder ebenfalls in der Schleife. Sollte Letzteres der Fall sein, entscheidet der Zustand von turn über den weiteren Verlauf. Enthält turn die Nummer des anderen Prozesses, wird das eigene Flag zurückgesetzt und gewartet bis turn die Nummer des eigenen Prozess hat. Damit erhält der andere Prozess die Möglichkeit, die Schleife zu verlassen (falls er sich darin befunden hat) und in den kritischen Abschnitt zu gelangen.

Nach dem kritischen Abschnitt des anderen Prozesses wird turn auf die Nummer des eigenen Prozesses gesetzt und das Flag des anderen Prozesses zurückgesetzt. Dadurch kann der eigene Prozess beide Warteschleifen verlassen und in seinen kritischen Abschnitt gelangen.

Beispiel

-> '''turn''' wird mit 0 initialisiert.
-> Prozess #0 bekommt den Prozessor: flag0 = true;
-> Prozess #1 bekommt den Prozessor: flag1 = true;
-> Prozess #0 bekommt den Prozessor: Eintritt in die Schleife
-> Prozess #1 bekommt den Prozessor: Eintritt in die Schleife
-> Prozess #0 bekommt den Prozessor: Die Bedingung turn != 0 wird nicht erfüllt
-> Prozess #1 bekommt den Prozessor: Die Bedingung turn != 1 wird erfüllt
-> Prozess #0 bekommt den Prozessor: Erneuter Eintritt in die Schleife, da flag1 gesetzt
-> Prozess #1 bekommt den Prozessor: flag1 = false;
-> Prozess #0 bekommt den Prozessor: Die Bedingung turn != 0 wird nicht erfüllt
-> Prozess #1 bekommt den Prozessor: Die Bedingung turn != 1 wird erfüllt
-> Prozess #0 bekommt den Prozessor: Eintritt in den kritischen Abschnitt, da flag1 nicht gesetzt
-> Prozess #0 bekommt den Prozessor: turn = 1;
-> Prozess #1 bekommt den Prozessor: flag1 = true;
-> Prozess #0 bekommt den Prozessor: flag0 = false;
-> Prozess #1 bekommt den Prozessor: Die Bedingung turn != 1 wird nicht erfüllt
-> Prozess #0 bekommt den Prozessor: Rücksprung zu Marke P0, flag0 = true
-> Prozess #1 bekommt den Prozessor: Eintritt in den kritischen Abschnitt, da flag0 nicht gesetzt
-> Prozess #0 bekommt den Prozessor: Eintritt in die Schleife
-> Prozess #1 bekommt den Prozessor: turn = 0;
-> Prozess #0 bekommt den Prozessor: Die Bedingung turn != 0 wird nicht erfüllt
-> Prozess #1 bekommt den Prozessor: flag1 = false;
-> Prozess #0 bekommt den Prozessor: Eintritt in den kritischen Abschnitt, da flag1 nicht gesetzt, turn = 1;
-> Prozess #1 bekommt den Prozessor: Rücksprung zu Marke P1, flag1 = true

Bedeutung

Im Gegensatz zu anderen Lösungen zur dezentralen Steuerung arbeitet der Dekker-Algorithmus aufgrund der Variable turn auch dann korrekt, wenn das Scheduling abwechselnd zwischen beiden Prozessen hin und her springt. Eine Vereinfachung findet sich im ebenfalls korrekt arbeitenden Peterson-Algorithmus. Der Nachteil der dezentralen Steuerung bleibt bestehen: Wartende Prozesse geben den Prozessor nicht ab, sondern beanspruchen ihn durch Busy waiting.