home *** CD-ROM | disk | FTP | other *** search
/ Knowledge & Learning / WISS_LERN.iso / doslern / computer / educard / bs___3.sti < prev    next >
Encoding:
Text File  |  1992-03-04  |  71.9 KB  |  2,207 lines

  1. YCPAA #!!# - Synchronisation -
  2. @CEInhalt
  3.  
  4. @CPDas Thema von BS___3 ist
  5. die Synchronisation paralleler Prozesse.
  6.  
  7. Start mit ⌐Parallelität@BS___3¬
  8. AHBAA #!!# Parallelität
  9. @EH                 Synchronisation paralleler Prozesse
  10. @HB
  11. @HEParallelität
  12. @HB
  13.   a) Parallelität im engeren Sinn
  14.      Unter Parallelität im engeren Sinn versteht man das gleichzeitige
  15.      Ablaufen mehrerer Prozesse.
  16.  
  17.   b) Parallelität im weiteren Sinn
  18.      Unter Parallelität im weiteren Sinn versteht man, daß Prozesse in
  19.      beliebiger, nicht festgelegter Reihenfolge, die im Grenzfall
  20.      sequentiell sein kann, ablaufen dürfen.
  21.  
  22.      Notation:@HA   PARBEGIN S1; S2; ...; Sn PAREND@HB
  23.  
  24.      Man darf dabei nicht annehmen, daß bei einem zweiten Durchlauf des
  25.      Programms die gleiche Reihenfolge wie beim ersten Durchlauf
  26.      eingehalten wird.
  27. @HB  c) Darstellung paralleler Abläufe
  28.      Es gibt versciedene Möglichkeiten, parallele Abläufe darzustellen.
  29.      Dies sind unter anderem:
  30.  
  31.      - Schreibweise einer Programmiersprache
  32.  
  33.        @HA   PARBEGIN S1; S2; ...; Sn PAREND@HB
  34.  
  35.      - Beschreibung durch einen Präzedenzgraphen
  36.  
  37.                           @HAS1
  38.               @HO┌───────────┼───────────┐
  39.              \│/         \│/         \│/
  40.               @HAS2          S3          S4
  41.               @HO└───────────┼───────────┘
  42.                          \│/
  43.                           @HAS5
  44.  
  45. @HB      - Ordnungsrelation, zum Beispiel "<" = zeitlich vor
  46.  
  47.         @HAS1 < S2 < S5
  48.         S1 < S3 < S5        @HB(siehe Präzedenzgraph von oben)@HA
  49.         S1 < S4 < S5
  50.  
  51.  
  52.            @HBsiehe auch ⌐Parallelismus@BS1¬
  53.  
  54.            @HBweiter mit ⌐Synchronisation II@BS___3¬
  55. AHBAA #!!# Synchronisation II
  56. @HENotwendigkeit der Synchronisation
  57. @HB
  58. Parallele Prozesse müssen synchronisiert werden, damit nicht mehrere
  59. Prozesse gleichzeitig auf exklusive ⌐Betriebsmittel@BS1¬ zugreifen können,
  60. so entstehende Fehler also ausgeschlossen sind.
  61.  
  62. Beispiel:
  63.   2 parallele Prozesse haben die Anweisung @HAx := x + 1@HB
  64.   Korrektes Ergebnis: @HAx := x + 1 + 1@HB
  65.   Ohne Synchronisation könnte es passieren, daß beide Prozesse gleich-
  66.   zeitig den Wert von x lesen, ihn um 1 erhöhen und abspeichern.
  67.   Das Ergebnis wäre : @HAx := x + 1@HB
  68.  
  69.   Damit das korrekte Ergebnis zustande kommt, muß der gleichzeitige
  70.   Zugriff auf den Wert x durch ⌐Synchronisation@BS1¬ ausgeschlossen werden.
  71.  
  72.  
  73.  
  74. @HEDefinition des Begriffs "Synchronisation"
  75. @HB
  76. Unter Synchronisation versteht man die gegenseitige zeitliche Abstimmung
  77. paralleler Prozesse beim Zugriff auf gemeinsame exklusiv benutzbare
  78. Betriebsmittel.
  79.  
  80. Die gegenseitige zeitliche Abstimmung bzw. den gegenseitigen zeitlichen
  81. Ausschluß kann man dadurch erreichen, daß man Befehlsfolgen zu unteilbaren
  82. Operationen zusammenfaßt, die nur sequentiell ablaufen können.
  83.  
  84. Eine andere Möglichkeit ist die des "kritischen Gebiets".
  85.  
  86.  
  87.  
  88.  
  89.  
  90.  
  91.  
  92. @HEDefinition des Begriffs "kritisches Gebiet"
  93. @HB
  94. Prozesse dürfen nicht gleichzeitig auf einen gemeinsamen Datenbereich oder
  95. ein gemeinsames, exklusives Betriebsmittel zugreifen.
  96.  
  97. Der Programmabschnitt, in dem ein Prozeß einen solchen Zugriff vornimmt
  98. (vornehmen will), heißt kritisches Gebiet.
  99.  
  100. Ein kritisches Gebiet ist dadurch gekennzeichnet, daß die Operationen in
  101. solch einem Gebiet nur von einem einzigen Prozeß ausgeführt werden dürfen.
  102. Ohne Synchronisationsmethoden könnten jedoch mehrere Prozesse gleichzeitig
  103. auf ihnen arbeiten.
  104.  
  105.            @HBweiter mit ⌐Interrupts sperren@BS___3¬
  106. AHBAA #!!# Interrupts sperren
  107. @EH             Synchronisation durch Sperren von Interrupts
  108. @HB
  109. @HESperren von Interrupts
  110. @HB
  111. Befehle höherer Programmiersprachen bestehen aus mehreren Elementar-
  112. operationen. Eine Synchronisationsmethode ist die, diese Befehle unteilbar
  113. zu machen, das heißt wenn ein Befehl ausgeführt wird, so werden alle
  114. dazugehörigen Elementaroperationen unmittelbar hintereinander ausgeführt.
  115. Es kann nicht innerhalb des Befehls zu einem Prozeßwechsel kommen.
  116.  
  117. Bei Rechenanlagen mit nur einer CPU (siehe ⌐Systemkern@BS1¬) erfolgen
  118. Prozeßwechsel auf Grund von ⌐Interrupt@BS2¬s. Um einen Befehl unteilbar zu
  119. machen, muß man also diese Interrupts sperren.
  120.  
  121. Vorteil:
  122.  
  123.    - Diese Synchronisationsmethode ist bei Anlagen mit nur einer einzigen
  124.      CPU anderen Verfahren vorzuziehen, da sie nicht so aufwendig ist.
  125. @HBNachteile:
  126.  
  127.    - Das Sperren kann nicht jeder Benutzer machen, sondern darf nur von
  128.      privilegierten Benutzern (Supervisor) gemacht werden.
  129.  
  130.    - Die Methode sollte nur angewendet werden, wenn zwischen dem Sperren
  131.      und der Freigabe von Interrupts nur wenige einfache Operationen, die
  132.      die CPU nur sehr, sehr kurz belegen, ausgeführt werden.
  133.  
  134.      Sonst könnten noch nicht behandelte Interrupts verloren gehen.
  135.  
  136.    - Die Methode ist nicht anwendbar auf Mehrprozessor-Systemen, da man
  137.      nur die Interrupts des eigenen Prozessors sperren kann, aber nicht
  138.      die der anderen.
  139.  
  140.                  weiter mit ⌐LOCK und UNLOCK@BS___3¬
  141.  
  142.                  siehe auch ⌐Unterbrechungssperre@BS2¬
  143. AHBAA #!!# LOCK und UNLOCK
  144. @EH                 Synchronisation durch LOCK und UNLOCK
  145. @HB
  146. LOCK und UNLOCK sind Befehle über die insbesondere Mehrprozessor-
  147. Anlagen verfügen. Sie sind wie folgt definiert:
  148.  
  149. @HALock (x)
  150.   LOCK : { IF x = 0 THEN x := 1
  151.                     ELSE GoTo LOCK } ;             {...} = unteilbar
  152.  
  153. Unlock (x)
  154.   UNLOCK : {x := 0};@HB
  155.  
  156. Die Variable x ist mit 0 initialisiert. Auf sie können alle Prozesse
  157. zugreifen.
  158.  
  159.  
  160.  
  161.  
  162. @HBBei dieser Synchronisationsmethode wird mit kritischen Gebieten
  163. gearbeitet. Der Lock-Befehl kennzeichnet den Beginn des kritischen
  164. Gebietes und der Unlock-Befehl dessen Ende.
  165.  
  166.      @HA    Lock (x);
  167.            @HLkritisches Gebiet@HA
  168.          Unlock (x);@HB
  169.  
  170. Beim Befehl Lock (x) wird die Variable x solange getestet bis sie den
  171. Wert 0 hat. Ist x = 0, so wird x auf 1 gesetzt und der Prozeß betritt
  172. das kritische Gebiet.
  173. Andere Prozesse die jetzt in das kritische Gebiet wollen, bleiben in der
  174. Warteschleife von Lock (x) hängen.
  175. Erst wenn der Prozeß das kritische Gebiet verlassen hat, was er durch den
  176. Unlock (x) Befehl anzeigt, kann ein anderer Prozeß das kritische Gebiet
  177. betreten (durch Unlock (x) wurde x ja wieder auf 0 gesetzt).
  178. Es kann auch nur genau einer wieder das kritische Gebiet betreten, da die
  179. Abfrage bei Lock (x) unteilbar ist.
  180. @HBVorteil gegenüber ⌐Interrupts sperren@BS___3¬:
  181.  
  182.    -  Diese Synchronisationsmethode kann sowohl auf Einprozessor- wie auch
  183.       auf Mehrprozessor-Anlagen laufen.
  184.  
  185. Nachteile:
  186.  
  187.    - Phänomen des @HPbusy waiting@HB oder auch @HPpolling@HB genannt:
  188.      Prozesse warten aktiv auf das Freiwerden des kritischen Gebietes.
  189.      Sie belasten den Prozessor mit ihrer ständigen Abfrage, obwohl er
  190.      inzwischen andere Arbeit erledigen könnte.
  191.  
  192.      Besser wäre es, wenn der wartende Prozeß stillgelegt würde und genau
  193.      dann wieder aktiviert würde, wenn das kritische Gebiet wieder frei
  194.      ist.
  195.  
  196.  
  197.  
  198. @HB   - Die Methode ist nicht sicher, d. h. sie kann zu ⌐Deadlock@BS1¬s führen.
  199.      Beispiel:
  200.        In einem System sind die Prozesse mit Prioritäten versehen und der
  201.        Prozessor wir dem Prozeß mit höchster Priorität zugewiesen.
  202.        Die Situation:
  203.  
  204.          Ein Prozeß niedriger Priorität befindet sich im kritischen Gebiet
  205.          und möchte es verlassen, also die Unlock-Operation ausführen.
  206.          Ein Prozeß höherer Priorität will das kritische Gebiet betreten.
  207.          Er beschäftigt mit seiner Abfrage ständig die CPU und gibt dem
  208.          Prozeß mit niedriger Priorität nie die Gelegenheit die CPU zu
  209.          benutzen um x auf 0 zu setzen und damit das kritische Gebiet zu
  210.          verlassen. Deadlock.
  211.  
  212.      Besser wäre es hier mit dynamischen Prioritäten zu arbeiten.
  213.      Die Priorität des wartenden Prozesses wird in festen Zeitintervallen
  214.      erniedrigt. Irgendwann hat der Prozeß die Möglichkeit, das kritische
  215.      Gebiet zu verlassen.
  216. @HEAnwendung in der Praxis
  217. @HB
  218. Auf Siemens Rechenanlagen der Serie 7000 gibt es für den LOCK-Befehl den
  219. Maschinenbefehl Test-and-Set (TS (x)). Er ist unteilbar und arbeitet auf
  220. der Adresse x. Er vergleicht den Inhalt der Speicherzelle mit der
  221. Adresse x mit Null und hält das Ergebnis in einem Register fest. Ist der
  222. Inhalt Null, so steht in dem Register eine 1 (für TRUE) und das Byte mit
  223. der Adresse x wird Bit für Bit auf 1 gesetzt.
  224.  
  225. Die Programmierung sieht dann so aus:
  226. @HA
  227.   x := 0                          X      DC X,'00'
  228.     :                                       :
  229.     :                                       :
  230.   Lock (x)                        LOOP:  TS X
  231.                                          BZ LOOP
  232.   @HLKritisches Gebiet                      Kritisches Gebiet@HA
  233.   Unlock (x)                             MVI X, 0
  234. @HBDie Anweisungsfolge
  235. @HA
  236.   TS X
  237.   BZ LOOP
  238. @HB
  239. sperrt auch den Bus, deshalb ist die Verwendung von
  240. @HA
  241.   BZ BRANCH ON ZERO
  242. @HB
  243. besser.
  244.  
  245.  
  246.           weiter mit ⌐Dekker@BS___3¬
  247. AHBAA #!!# Dekker
  248. @EH                       Synchronisation nach Dekker
  249. @HB
  250. Wie schon bei der ⌐Synchronisation@BS1¬ mit ⌐LOCK und UNLOCK@BS___3¬ erfolgt
  251. diese auch hier mit Synchronisations-Variablen, also Sprachelementen, die
  252. in allen Sprachen vorkommen.
  253.  
  254. Es werden im weiteren nur zyklisch, parallel arbeitende Prozesse
  255. betrachtet, das heißt Prozesse bewerben sich immer gleichzeitig um das
  256. selbe kritische Gebiet.
  257.  
  258.  
  259.  
  260.  
  261.  
  262.  
  263.  
  264.  
  265.  
  266. @HBBei der Lösung des Synchronisationsproblems müssen folgende Forderungen
  267. beachtet werden:
  268.  
  269.   1. Die Lösung soll symmetrisch sein, das heißt die Prozesse sollen
  270.      gleich aufgebaut sein.
  271.  
  272.   2. Die Arbeitsgeschwindigkeit der Prozesse darf keine Rolle spielen.
  273.  
  274.   3. Hält ein Prozeß außerhalb des kritischen Gebietes an (er stirbt), so
  275.      darf er nicht die anderen Prozesse blockieren.
  276.  
  277.   4. Wollen mehrere Prozesse gleichzeitig das kritische Gebiet betreten,
  278.      so darf dies nur genau einem erlaubt werden.
  279.  
  280. Die einzigen unteilbaren Operationen sind hier:
  281.   a) Lesezugriff auf den Speicher
  282.   b) Schreibzugriff auf den Speicher
  283.  
  284. @HESynchronisationslösung für 2 parallele Prozesse (nach Dekker)
  285. @HA
  286. VAR
  287. s1, s2, Turn : Integer;
  288. BEGIN
  289.   s1 := 1;          @HB(* 1 bewirbt sich nicht              *)@HA
  290.   s2 := 1;          @HB(* 2 bewirbt sich nicht              *)@HA
  291.   Turn := 1;        @HB(* Kritisches Gebiet KG von 1 belegt *)@HA
  292.  
  293.  
  294.  
  295.  
  296.  
  297.  
  298.  
  299.  
  300.  
  301.  
  302.  
  303.   @HAPARBEGIN
  304.     process_1 : CYCLE                process_2 : CYCLE
  305.       BEGIN                            BEGIN
  306.         s1 := 0;                         s2 := 0;    @HB(* Bewerbung um KG *)
  307. @HA        WHILE s2 = 0 DO                  WHILE s1 = 0 DO
  308.           IF Turn = 2 THEN                 IF Turn = 1 THEN
  309.             BEGIN                            BEGIN   @HB(* Warten bis frei *)
  310. @HA              s1 := 1;                         s2 := 1; @HB(* Bew. zurück  *)
  311. @HA              WHILE Turn = 2 DO;               WHILE Turn = 1 DO;
  312.               s1 := 0;                         s2 := 0; @HB(* Bew. um KG   *)
  313. @HA            END;                             END;
  314.         @HLKritisches Gebiet                Kritisches Gebiet; @HB(* hinein   *)
  315. @HA        Turn := 2;                       Turn := 1;     @HB(* KG freigeben *)
  316. @HA        remainder of cycle 1             remainder of cycle 2
  317.       END;                             END;  
  318.   PAREND
  319. END;
  320. @HBMan kann den Algorithmus folgendermaßen beschreiben:
  321.  
  322. @HB  Bewirb dich um kritisches Gebiet.            @HAs1 := 0;
  323. @HB  Hat der andere Prozeß sich beworben          @HAWHILE s2 = 0 DO
  324. @HB  und ist im kritischen Gebiet,                @HA  IF Turn = 2 THEN
  325. @HB  dann ziehe eigene Bewerbung zurück           @HA    BEGIN
  326. @HB  und warte bis er KG verlassen hat.           @HA      s1 := 1;
  327. @HB                                               @HA      WHILE Turn = 2 DO;
  328. @HB  Hat er es verlassen, bewerbe dich erneut.    @HA      s1 := 0;
  329. @HB                                               @HA    END;
  330. @HB  Hat der andere Prozeß sich nicht beworben,
  331. @HB  betrete das kritische Gebiet.                @HL   kritisches Gebiet
  332. @HB  Hast du das kritische Gebiet verlassen,
  333. @HB  sage dies dem anderen Prozeß                 @HATurn = 2;
  334. @HB  und lösche deine Bewerbung.                  @HAs1 := 1;
  335.  
  336.  
  337.                  @HBweiter mit ⌐Dijkstra@BS___3¬
  338. AHBAA #!!# Dijkstra            *
  339. @HESynchronisationslösung für N parallele Prozesse (nach Dijkstra)
  340. @HA
  341. PROGRAM Process_i (b, c, k);
  342.  
  343.   CONST
  344.   MöchteGern = ...; @HB(* Antragsteller für das kritische Gebiet *)@HA
  345.   N = ...;          @HB(* Anzahl Prozesse                        *)@HA
  346.  
  347.   TYPE
  348.   Prozeß-Menge = 1..N;
  349.  
  350.   VAR
  351.   Nicht-Bewerber : SET OF Prozeß-Menge; @HB(* wollen gar nicht hinein  *)@HA
  352.   NotMember      : SET OF Prozeß-Menge; @HB(* sind nicht im Kr. Gebiet *)@HA
  353.   Y : SET OF Prozeß-Menge;              @HB(* ??? *)@HA
  354.   Auserwählter : Prozeßmenge;           @HB(* dürfte wenn er will      *)@HA
  355.   KrGebietFrei : Boolean;               @HB(* wenn ja dann los         *)@HA
  356.  
  357. @HABEGIN
  358.   WHILE TRUE DO
  359.     BEGIN @HB(* Bewerbung um kritisches Gebiet *)@HA
  360.       KrGebietFrei := FALSE;
  361.       Nicht-Bewerber := Nicht-Bewerber - {MöchteGern};
  362.       Y := {1..N} - {MöchteGern};               @HB(* nie benutzt ??? *)@HA
  363.       REPEAT @HB(* geeigneten Bewerber suchen *)@HA
  364.         IF Auserwählter <> MöchteGern THEN
  365.           BEGIN @HB(* MöchteGern wird NotMember *)@HA
  366.             NotMember := NotMember + {MöchteGern};
  367.             IF Auserwählter IN Nicht-Bewerber THEN
  368.               Auserwählter := MöchteGern;            
  369.           END   @HB(* MöchteGern wird NotMember *)@HA
  370.         ELSE
  371.           BEGIN
  372.             NotMember := NotMember - {MöchteGern};
  373.             KrGebietFrei := (NotMember + {MöchteGern}) = {1..N};  
  374.           END;
  375. @HA      UNTIL KrGebietFrei;
  376.       @HLK R I T I S C H E S   G E B I E T@HA
  377.       NotMember := NotMember + {MöchteGern}; @HB(* bin wieder zurück  *)@HA
  378.       Nicht-Bewerber := Nicht-Bewerber + {MöchteGern} @HB(* erledigt *)@HA
  379.     END;  @HB(* Bewerbung um kritisches Gebiet *)@HA
  380. END.@HB
  381.  
  382. @HBBeschreibung des Algorithmusses:
  383.                                           @HA:
  384.                                           @HAWHILE TRUE DO
  385.                                           @HA  BEGIN
  386.                                           @HA    ok := FALSE:
  387. @HBBewerbe dich um das kritische Gebiet      @HA    b := b - {i};
  388.                                           @HA    REPEAT
  389. @HBWenn du nicht der ausgewählte Prozeß zum  @HA      IF k <> i THEN
  390. @HBBetreten des kritischen Gebiets bist,     @HA        BEGIN
  391. @HBdann wirst du in die Menge der Bewerber   @HA          c := c + {i};
  392. @HBaufgenommen
  393. @HBund wenn der ausgewählte Prozeß sich      @HA          IF k ε b THEN
  394. @HBnicht beworben hat,
  395. @HBdann wirst du zum ausgewählten Prozeß.    @HA            k := i
  396.                                           @HA        END
  397.                                           @HA      ELSE
  398. @HBWenn du der ausgewählte Prozeß bist,      @HA        BEGIN
  399. @HBdann teile dies den anderen Bewerbern mit @HA          c := c - {i};
  400.                                           @HA          ok := (c + {i} = {1..N});
  401.                                           @HA        END;
  402. @HBund wenn das kritische Gebiet frei ist,   @HA    UNTIL ok;
  403. @HBbetrete es.
  404.                                           @HL         kritisches Gebiet
  405.  
  406. @HBHast du es verlassen,                     @HA    c := c + {i};
  407. @HBso teile dies den Bewerbern mit und
  408. @HBziehe deine Bewerbung zurück.             @HA    b := b + {i};
  409.                                           @HA  END;
  410.  
  411. @HBBemerkungen:
  412.  
  413.    - Der gegenseitige Ausschluß ist gewährleistet.
  414.      Der Prozeß, der im kritischen Gebiet ist, hat sich vorher aus der
  415.      Menge der Bewerber gestrichen.
  416.  
  417.      Will ein weiterer Prozeß das kritische Gebiet betreten, so streicht
  418.      auch er sich aus der Menge der Bewerber, dadurch kann ok aber nicht
  419.      TRUE werden und er bleibt in der REPEAT-Schleife.
  420.  
  421.    - Es ist auch ausgeschlossen, daß niemand das kritische Gebiet betritt,
  422.      obwohl Bewerber da wären.
  423.  
  424.      Gelangen mehrere Prozesse gleichzeitig in den ELSE-Zweig, so kann ok
  425.      nicht TRUE werden und sie müssen die REPEAT-Schleife erneut durch-
  426.      laufen. Dabei gilt aber nur für einen einzigen Prozeß k = i. Dieser
  427.      kommt erneut in den ELSE-Zweig, aber als einziger, kann somit ok auf
  428.      TRUE setzen und das kritische Gebiet betreten.
  429. @HB   - Es ist möglich, daß ein Prozeß verhungert, da nicht bestimmt festge-
  430.     legt ist, wer k auf dessen Prozeßnummer setzt.
  431.  
  432. @HEVerbesserung
  433. @HB
  434. Um die Möglichkeit des Verhungerns auszuschließen, gibt es von einigen
  435. Leuten Verbesserungsvorschläge zum Algorithmus von Dijkstra.
  436.  
  437.   a) @HPKnuth                         N-1@HB
  438.      Ein Prozeß muß auf höchstens @HP2    - 1@HB Besuche anderer Prozesse ihres
  439.      kritischen Gebietes warten, bis er selbst eines betreten kann.
  440.  
  441.   b) @HPde Bruijn                                N * (N-1)@HB
  442.      Verbesserung von Knuths Algorithmus auf @HP───────────@HB Besuche anderer,
  443.      bevor man selbst eins betreten kann.         @HP2@HB
  444.  
  445.   c) @HPEisenberg & Mc Guire@HB
  446.      Verbesserung von Knuths Algorithmus auf @HPN - 1@HB Besuche anderer.
  447.   d) @HPLamport@HB
  448.      Reihenfolge des Betretens des kritischen Gebiets in @HPFCFS@HB.
  449.      In diesem Fall greifen alle Prozesse auf die Daten der anderen
  450.      Prozesse lediglich lesend zu. Nur die eigenen Daten können verändert
  451.      werden. Dies war bei den anderen nicht der Fall.
  452.  
  453.                  weiter mit ⌐Semaphore@BS___3¬
  454. AHBAA #!!# Semaphore
  455. @EH                     Synchronisation mit Semaphoren
  456. @HB
  457. Die bisher beschriebenen Synchronisationsmethoden sind viel zu schwer-
  458. fällig, zu undurchsichtig und haben den großen Nachteil des Pollings.
  459.  
  460. Dijkstra hat eine ökonomischere Lösung gefunden. Er hat einen neuen
  461. Datentyp "Semaphor" eingeführt, mit dem man wartende Prozesse schlafen
  462. legen kann, bis das Ereignis, auf das sie warten eintrifft. Dann werden
  463. sie wieder geweckt.
  464.  
  465. Man unterscheidet zwei Typen von Semaphoren:
  466.  
  467.   a) die @HPbinären Semaphore@HB    : Wertebereich 0..1
  468.  
  469.   b) die @HPallgemeinen Semaphore@HB: Wertebereich 0..u (beliebig)
  470.  
  471.  
  472. Allgemeine Semaphore sind zurückzuführen auf binäre Semaphore.
  473. @HBEs gibt 3 verschiedene @HPOperationen auf Semaphore@HB:
  474.  
  475.   a) Initialisierung
  476.   b) P-Operation
  477.   c) V-Operation
  478.  
  479. @HPInitialisierung@HB
  480.   Initialisiert wird eine Semaphorvariable (meistens) mit 1, z. B. s := 1
  481.  
  482. @HPP-Operation@HB
  483.   Die P-Operation ist unteilbar. Sie bewirkt, daß die Semaphorvariable
  484.   um 1 erniedrigt wird (dekrementiert wird).
  485.   Implementierung der P-Operation:
  486. @HA
  487.   P (s) = { s := s - 1;                      @HI{ ... } = unteilbar@HA
  488.             IF s < 0 THEN Warte (s) }
  489.  
  490.  
  491. @HPV-Operation@HB
  492.   Die V-Operation ist ebenfalls unteilbar und bewirkt, daß die Semaphor-
  493.   variable um 1 erhöht wird (inkrementiert wird).
  494.   Implementierung der V-Operation:
  495. @HA
  496.   V (s) = { s := s + 1;
  497.             If s ≤ 0 THEN Wecke (s) }
  498.  
  499. @HPWarte (s)@HB
  500.   Derjenige Prozeß, der die P-Operation ausführen will, wird schlafen
  501.   gelegt (angehalten). In seiner Zustandsbeschreibung wird notiert, daß
  502.   er auf eine V-Operation auf das Semaphor s wartet.
  503.  
  504. @HPWecke (s)@HB
  505.   Ein Prozeß, der angehalten wurde und auf eine V-Operation auf das
  506.   Semaphor s wartet, wird geweckt (aktiv gesetzt). Er kann sofort weiter-
  507.   rechnen.
  508.  
  509.   @HBWarten mehrere Prozesse auf eine V-Operation auf dasselbe Semaphor,
  510.   darf nur einer von ihnen geweckt werden. Die Auswahl aus der Menge der
  511.   wartenden Prozesse kann zufallsmäßig geschehen oder, was fairer ist,
  512.   nach dem FIFO-Prinzip. Im letzteren Fall ist gewährleistet, daß ein
  513.   Prozeß nach einer endlich langen Wartezeit geweckt wird.
  514.  
  515. Bemerkungen:
  516.  
  517.    - Bei dieser Implementierung der P- und V-Operationen kann das
  518.      Betriebssystem an der Größe von s erkennen, ob und wieviele Prozesse
  519.      auf V (s) warten. Es ist also von Vorteil, für Semaphore auch
  520.      negative Werte zuzulassen.
  521.  
  522.  
  523.  
  524.  
  525.  
  526.  
  527. @HB   - Semaphore dienen in erster Linie dem Schutz kritischer Gebiete:
  528. @HA
  529.      Process_1: CYCLE                    Process_2: CYCLE
  530.        BEGIN                               BEGIN
  531.          P (s);                              P (s)
  532.            @HLkritisches Gebiet 1                 kritisches Gebiet 2@HA
  533.          V (s);                              V (s);
  534.          :                                   :
  535.          :                                   :
  536.        END                                 END
  537.  
  538.  
  539.              @HBweiter mit ⌐Erzeuger-Verbraucher@BS___3¬
  540. AHBAA #!!# Erzeuger-Verbraucher
  541. @HEErzeuger-Verbraucher-Problem
  542. @HB
  543. Beim Erzeuger-Verbraucher-Problem geht es um den Nachrichtenaustausch
  544. zwischen Erzeugern (den Nachrichtenproduzenten) und Verbrauchern (den
  545. Nachrichtenkonsumenten). Der @HPErzeuger@HB produziert Nachrichten und legt
  546. diese in einem Puffer ab. Der @HPVerbraucher@HB holt die Nachrichten aus dem
  547. Puffer und verarbeitet sie. Der @HPPuffer@HB ist ein globaler Speicher
  548. variabler Länge.
  549.  
  550. Forderungen, die an die Lösung gestellt werden:
  551.  
  552.   1. Prozesse sollen sich beim Zugriff auf den Puffer nicht gegenseitig
  553.      stören.
  554.   2. Es darf nichts in den Puffer gelegt werden, wenn er voll ist.
  555.   3. Es darf nichts aus dem Puffer geholt werden, wenn er leer ist.
  556.   4. Die Arbeitsgeschwindigkeit von Erzeugern und Verbrauchern soll
  557.      unabhängig voneinander sein.
  558.  
  559. @HETriviale Lösung für das Erzeuger-Verbraucher-Problem@HB
  560.  
  561. @HAVAR
  562. Message, Leer : semaphor;
  563.  
  564. Init (Message := 0);
  565. Init (Leer := 1);
  566.  
  567. Erzeuger    : "erzeuge Nachricht";
  568.               P (Leer);
  569.               "lege Nachricht in Puffer";
  570.               V (Message);
  571.  
  572. Verbraucher : P (Message);
  573.               "hole Nachricht aus Puffer";
  574.               V (Leer);
  575.               "verarbeite Nachricht";
  576.  
  577. @HBAuf diese Weise wird eine sequentielle Reihenfolge erzwungen.
  578. Die Lösung verstößt damit gegen die Forderung der Unabhängigkeit der
  579. Arbeitsgeschwindigkeiten für Erzeuger und Verbraucher.
  580.  
  581. Wendet man das Erzeuger-Verbraucher-Problem zum Beispiel auf eine Druck-
  582. ausgabe an, so kommt es zum "Stottern" des Druckers. Der Erzeuger
  583. produziert Daten für den Drucker und legt sie im Druckerpuffer ab. Der
  584. Verbraucher holt die Daten aus dem Druckerpuffer und gibt sie auf den
  585. Drucker. Bei einer sequentiellen Reihenfolge kann erst wieder etwas in den
  586. Puffer gelegt werden, wenn er vom Verbraucher geleert worden ist. Die
  587. Folge ist, daß der Drucker stottert.
  588.  
  589. Um dies zu vermeiden, verwendet man statt einem zwei Puffer, die ab-
  590. wechselnd gefüllt und geleert werden. Zunächst wird der Puffer_1 gefüllt.
  591. Während Puffer_1 geleert wird, wird Puffer_2 gefüllt. Ist Puffer_2
  592. schneller gefüllt als Puffer_1 geleert, so muß der Erzeuger anhalten. Der
  593. Verbraucher kann allerdings, nachdem er Puffer_1 geleert hat, direkt
  594. Puffer_2 leeren.
  595. @HBDas Füllen des einen und das Leeren des anderen Puffers kann parallel
  596. erfolgen.
  597.  
  598. @HELösung des Erzeuger-Verbraucher-Problems für K Puffer
  599. (Kreispuffer mit K Einheiten)
  600.  
  601. @HAVAR
  602. Leer, Voll : Semaphor;
  603. Puffer : ARRAY [0..K-1] OF INFO;
  604. EX : Integer;                     @HB(* Erzeuger-Index    *)@HA
  605. VX : Integer;                     @HB(* Verbraucher-Index *)@HA
  606.  
  607. Init (Leer := K);
  608. Init (Voll := 0);
  609. EX := 0;
  610. VX := 0;
  611.  
  612.  
  613. @HAErzeuger    : "erzeuge Nachricht";
  614.               P (Leer);
  615.               Puffer [EX] := erzeugte Nachricht;
  616.               EX := Succ (EX);     @HB(* modulo K *)@HA
  617.               V (Voll);
  618.  
  619. Verbraucher : P (Voll);
  620.               "hole Nachricht aus Puffer [VX];
  621.               VX := Succ (VX);     @HB(* modulo K *)@HA
  622.               V (Leer);
  623.               "verarbeite Nachricht";
  624.  
  625.  
  626.                 @HBweiter mit ⌐Leser-Schreiber@BS___3¬
  627. AHBAA #!!# Leser-Schreiber
  628. @HELeser-Schreiber-Problem
  629.  
  630. @HPProblem 1:@HB
  631.  
  632. Beim Leser-Schreiber-Problem gibt es zwei Arten von Prozessen,
  633. Leser und Schreiber. Sie greifen auf ein gemeinsames Betriebsmittel
  634. zu, zum Beispiel eine Datei. Dabei gelten folgende Regeln:
  635.  
  636.   a) Es können mehrere Leser gleichzeitig aktiv sein (also lesen),
  637.      aber zum selben Zeitpunkt darf niemand schreiben.
  638.  
  639.   b) Es darf genau ein Schreiber gleichzeitig aktiv sein (also schreiben),
  640.      aber zum selben Zeitpunkt darf niemand lesen.
  641.  
  642.   c) Bei Problem 1 gilt außerdem:
  643.      Sollte sich während des Zugriffs von Lesern ein Schreiber
  644.      bewerben, so muß er warten bis kein Leser mehr aktiv ist.
  645.      Leser werden hier also bevorzugt.
  646. @HELösung zu Problem 1:@HB (mit ⌐Semaphor@BS1¬en)
  647. @HA
  648. VAR
  649. RC : Integer;                         @HB(* reader counter            *)@HA
  650. W, Mutex : Semaphor;                  @HB(* mutex exclusion           *)@HA
  651.                                       @HB(* = gegenseitiger Ausschluß *)@HA
  652. Init (W := 1);
  653. Init ( Mutex := 1);
  654. RC := 0;
  655.  
  656.  
  657.  
  658.  
  659.  
  660.  
  661.  
  662.  
  663.  
  664. @HAWriter : P (W);                @HB(* ist jemand am Lesen oder Schreiben ?  *)
  665. @HA         "schreiben";          @HB(* falls nein, dann los                  *)
  666. @HA         V (W);                @HB(* Message: Ich bin fertig.              *)
  667. @HA
  668. @HAReader : P (Mutex);            @HB(* ändert gerade einer RC ?              *)
  669. @HA         RC := RC + 1;         @HB(* falls nein, dann los                  *)
  670. @HA         IF RC = 1 THEN P (W); @HB(* ich der einzige -> schreiben sperren  *)
  671. @HA                               @HB(* eventuell auf einen Schreiber warten  *)
  672. @HA         V (Mutex);            @HB(* fertig mit Ändern von RC              *)
  673. @HA         "lesen";
  674. @HA         P (Mutex);            @HB(* Zugriff auf RC schützen               *)
  675. @HA         RC := RC - 1;
  676. @HA         IF RC = 0 THEN V (W); @HB(* kein Leser mehr -> schreiben freigeben*)
  677. @HA         V (Mutex);            @HB(* fertig mit Ändern von RC              *)
  678.  
  679.  
  680.  
  681.  
  682. @HB
  683. Bemerkungen:
  684.  
  685.    - Beim Schreiber ist das Schreiben das kritische Gebiet,
  686.      während beim Leser die Veränderung der Variablen RC vor
  687.      gleichzeitigem Zugriff geschützt werden muß.
  688.  
  689.    - Welche Art von Prozeß durch die V (W)-Operation geweckt wird
  690.      ist nicht deterministisch festgelegt. Dadurch kann es
  691.      passieren, daß die Schreiber verhungern (nämlich dann, wenn
  692.      während ein Leser aktiv ist, mindestens ein weiterer Leser
  693.      dazu kommt).
  694.  
  695.  
  696.  
  697.  
  698.  
  699.  
  700. @HPProblem 2:@HB
  701.  
  702.   a)  ┐
  703.       ├ wie bei Problem 1
  704.   b)  ┘
  705.  
  706.   c) wird geändert, es soll gelten:
  707.      Schreiber werden bevorzugt behandelt, d. h. sobald ein Schreiber
  708.      darauf wartet, aktiviert zu werden (er schläft), dürfen keine
  709.      weiteren Leser mehr angenommen werden.
  710.  
  711.  
  712.  
  713.  
  714.  
  715.  
  716.  
  717.  
  718. @HELösung 2:@HB
  719. @HAVAR
  720. rc : Integer;             @HB(* reader counter                        *)@HA
  721. wc : Integer;             @HB(* writer counter                        *)@HA
  722. mutex1 : Semaphor;        @HB(* exklusiver Zugriff auf rc             *)@HA
  723. mutex2 : Semaphor;        @HB(* exklusiver Zugriff auf wc             *)@HA
  724. mutex3 : Semaphor;        @HB(* Bevorzugung von Schreibern vor Lesern *)@HA
  725. w      : Semaphor;        @HB(* Schutz vor Schreiben beim Lesen und   *)@HA
  726.                           @HB(* Schutz vor Lesen beim Schreiben       *)@HA
  727. r      : Semaphor;        @HB(* Unterbrechung des Lesestroms          *)@HA
  728.  
  729. Init (mutex1 := 1);
  730. Init (mutex2 := 1);
  731. Init (mutex3 := 1);
  732. Init (w      := 1);
  733. Init (r      := 1);
  734. rc := 0;
  735. wc := 0;@HB
  736.  
  737. @HAReader : P (mutex3);                 @HB(* hier bleibt der nächste Leser   *)
  738. @HA                                     @HB(* schon stecken                   *)
  739. @HA           P (r);                    @HB(* darf ich lesen ?                *)
  740. @HA                                     @HB(* jetzt kann ein weiteres P (r)   *)
  741.                                      @HB(* nur von einem Schreiber kommen  *)
  742. @HA             P (mutex1);
  743.                rc := rc + 1;
  744.                IF rc = 1 THEN P (w);
  745.              V (mutex1);
  746.            V (r);                     @HB(* Falls Schreiber wartet         *)
  747. @HA         V (mutex3);
  748.          "lesen";
  749.          P (mutex1);
  750.            rc := rc - 1;
  751.            IF rc = 0 THEN V (w);
  752.          V (mutex1);@HB
  753.  
  754.  
  755. @HAWriter : P (mutex2);
  756.            wc := wc + 1;             @HB(* die beiden Operationen sind    *)
  757. @HA           IF wc = 1 THEN P (r);     @HB(* geteilt ! Das ist gefährlich!  *)
  758. @HA         V (mutex2);
  759.          P (w);
  760.            "schreiben";
  761.          V (w);
  762.          P (mutex2);
  763.            wc := wc - 1;
  764.            IF wc = 0 THEN V (r);
  765.          V (mutex2);@HB
  766.  
  767.  
  768.  
  769.  
  770.  
  771.  
  772.  
  773. @HBBemerkungen:
  774.    - Befindet sich ein Leser zwischen der P (r)- und der V (r)-Operation,
  775.      dann wird durch mutex3 erreicht, daß wenn überhaupt jemand auf die
  776.      V (r)-Operation wartet, dies nur ein Schreiber sein kann. Ein Leser
  777.      bleibt schon in P (mutex3) stecken.
  778.  
  779.    - Auf einen Schreiber kann wegen P (r) und P (mutex3) nur höchstens ein
  780.      Leser warten und/oder wegen P (w) viele Schreiber.
  781.  
  782.    - Läßt sich der 1. Schreiber nach der Ausführung von wc := wc + 1 bis
  783.      zur Ausführung von P (r) Zeit, dann können im Gegensatz zur Aufgaben-
  784.      stellung während dieser Zeit beliebig viele Leser das System
  785.      betreten !
  786.  
  787.    - Es kann doch immer nur einer gleichzeitig lesen, wegen P (mutex3) ???
  788.      -> Verletzung von Regel a) ???
  789.  
  790.  
  791.   siehe auch:                    weiter mit ⌐5 Philosophen@BS___3¬
  792.   ⌐REGION@BS___3¬
  793.   ⌐Monitore@BS1¬
  794.   ⌐Monitore II@BS___3¬
  795. AHBAA #!!# 5 Philosophen
  796.                                @HM┌────┐@HB
  797.                                @HM│  0 │@HB
  798.                      @HJ└┼┘@HB       @HM└────┘@HB       @HJ└┼┘@HB
  799.                      @HJ │@HB1                     @HJ│@HB0
  800.  
  801.                 @HM┌────┐@HB                        @HM┌────┐@HB
  802.                 @HM│  1 │@HB        @HPSPAGHETTI@HB       @HM│  4 │@HB
  803.                 @HM└────┘@HB        @HO≈≈≈≈≈≈≈≈≈       @HM└────┘@HB
  804.                     @HJ└┼┘@HB                      @HJ└┼┘@HB
  805.                      @HJ│@HB2                       @HJ│@HB4
  806.                         @HM┌────┐@HB   @HJ└┼┘@HB  @HM┌────┐@HB
  807.                         @HM│  2 │@HB    @HJ│@HB3  @HM│  3 │@HB
  808.                         @HM└────┘@HB        @HM└────┘@HB
  809.  
  810. Beim 5 Philosophen-Problem wird der Lebensrhythmus von 5 Philosophen
  811. betrachtet, der im Abwechseln von Denken und Essen besteht. Beide Tätig-
  812. keiten schließen sich gegenseitig aus.
  813.  
  814. @HBDas Essen erfolgt an einem kreisförmigen Tisch, auf dem 5 Teller stehen
  815. und zwischen jedem Teller liegt eine Gabel. Jeder Philosoph i benötigt
  816. 2 Gabeln zum Essen, sowohl die links neben seinem Teller als auch die
  817. rechts davon (gabel [i] und gabel [(i+1) mod 5]).
  818.  
  819. Die Gabeln stellen ein exklusives ⌐Betriebsmittel@BS1¬ dar, auf das der Zugriff
  820. synchronisiert werden muß. Dies geschieht bei ⌐Semaphor@BS1¬en mit
  821. P- und V-Operationen. Andere Lösungsmöglichkeiten sind durch
  822.   ⌐REGION@BS___3¬-Anweisungen oder
  823.   ⌐Monitore@BS1¬ gegeben.
  824.  
  825. @HELösungsansätze:@HB
  826.  
  827.  
  828.  
  829.  
  830.  
  831.  
  832. @HEAnsatz 1:@HB
  833.  
  834.   @HAphilosoph_i : CYCLE
  835.     BEGIN
  836.       "denken";
  837.       P (gabel [i]);
  838.         P (gabel [i+1]);          @HB(* i+1 heißt natürlich (i+1) mod 5   *)
  839. @HA          "essen";
  840.         V (gabel [i+1]);
  841.       P (gabel [i]);
  842.     END;
  843.  
  844. @HBDieser Ansatz ist deadlockgefährdet. Setzen sich alle 5 Philosophen
  845. gleichzeitig an den Tisch und jeder nimmt seine linke Gabel (gabel [i]),
  846. dann sind alle Gabeln belegt aber keiner kann essen. Jeder wartet darauf,
  847. daß sein rechter Nachbar dessen linke Gabel freigibt ==> Die Philosophen
  848. erwartet ein schweres Schicksal, Deadlock.
  849.  
  850. @HEAnsatz 2:
  851.  
  852. @HBMan verlegt den Zugriff auf die Gabeln in ein geschütztes kritisches
  853. Gebiet:
  854. @HA
  855.            :
  856.       P (mutex);
  857.         P (gabel [i]);
  858.         P (gabel [i+1]);
  859.       V (mutex);
  860.            :
  861. @HB
  862. Diese Lösung ist nicht optimal, denn es kann vorkommen, daß ein Philosoph
  863. warten muß, obwohl seine beiden Gabeln frei sind, weil ein anderer Philo-
  864. soph noch auf eine seiner Gabeln wartet. Dieser versperrt das kritische
  865. Gebiet. Man hat also eine schlechte Auslastung der Betriebsmittel.
  866.  
  867.  
  868. @HBFalls man versucht, Lösung 1 zu verbessern, indem man die Gabeln
  869. hierarchisch anordnet und verlangt, daß jeder Philosoph zuerst die Gabel
  870. mit der kleineren Nummer ergreift, kann es zwar nicht mehr passieren, daß
  871. alle Gabeln vergeben sind und keiner ißt, aber das Manko der 2. Lösung
  872. (ein Philosoph muß warten, obwohl seine beiden Gabeln frei wären) bleibt.
  873.  
  874. @HEAnsatz 3:@HB
  875.  
  876. Man führt Zustandsvariablen z [i] für jeden Philosophen i ein:
  877.  
  878.    Zustand 0 : denken
  879.    Zustand 1 : hungrig sein
  880.    Zustand 2 : essen
  881.  
  882.    ... -> Zustand 0 -> Zustand 1 -> Zustand 2 -> Zustand 0 -> ...
  883.  
  884. Auf diese Weise will man gewährleisten, daß ein Philosoph essen kann,
  885. wenn seine Gabeln frei sind.
  886. @HBDer Lebenszyklus eines Philosophen besteht jetzt in dem Zyklus
  887. denken, hungrig sein, essen, denken, ...
  888.  
  889. Um vom Zustand 1 in den Zustand 2 zu gelangen müssen folgende
  890. Bedingungen erfüllt sein:
  891.  
  892.   1) @HPz [i]   =  1@HB        Philosoph i muß hungrig sein
  893.  
  894.   2) @HPz [i-1] <> 2@HB        sein linker Nachbar  darf nicht essen
  895.  
  896.   3) @HPz [i+1] <> 2@HB        sein rechter Nachbar darf nicht essen
  897.  
  898. Ein Philosoph kann nur essen, wenn diese 3 Bedingungen gleichzeitig
  899. gelten. Er muß also die Zustände seiner beiden Nachbarn prüfen. Wenn
  900. beide nicht essen, so darf er es tun.
  901. Falls er warten muß, so kann ihn nur der Nachbar wecken, der seine
  902. Gabel zurückgibt. Dieser muß daher, wenn er seine Gabeln zurückgibt,
  903. testen, ob seine Nachbarn essen wollen und sie gegebenenfalls wecken.
  904.  
  905. @HEAlgorithmus:
  906.  
  907. @HAVAR
  908. mutex   : Semaphor;
  909. z       : ARRAY [0..4] OF 0..2;
  910. i       : Integer;
  911. privsem : ARRAY [0..4] OF Semaphor;
  912.  
  913. Init (mutex := 1);
  914. FOR i := 0 TO 4 DO z [i] := 0;
  915. FOR i := 0 TO 4 DO Init (privsem [i] := 0);
  916.  
  917.  
  918.  
  919.  
  920.  
  921.  
  922. @HAPhilosoph_i : CYCLE
  923.   BEGIN
  924.     "denken";
  925.     P (mutex);
  926.       "hungrig werden": z [i] := 1;
  927.       "teste Zustände der Nachbarn:
  928.        Wenn sie nicht essen, so ist dein neuer Zustand essen
  929.        und mache P (privsem [i])";
  930.     V (mutex);
  931.     P (privsem [i]);
  932.     "essen";
  933.     P (mutex);
  934.       "denken": z [i] := 0;
  935.       "teste ob linker Nachbar essen will:
  936.        Wenn er will, wecke ihn: V (privsem [i-1])";
  937.       "teste ob rechter Nachbar essen will:
  938.        Wenn er will, wecke ihn: V (privsem [i+1])";
  939.     V (mutex);
  940. @HA  END;@HB
  941.  
  942. @HBBemerkungen:
  943.    - Durch die beiden P (privsem [i]) legt sich jeder Philosoph gleich
  944.      zweimal schlafen und muß erst durch seine beiden Nachbarn geweckt
  945.      werden, bevor er endlich essen kann. ???
  946.  
  947.    - Ein Philosoph, der mit dem Essen fertig ist, weckt seine beiden
  948.      Nachbarn. Wenn ihm dann gleich darauf einfällt, wieder essen zu
  949.      wollen, so muß er erst warten, bis seine Nachbarn damit fertig sind,
  950.      falls diese während seiner Essenszeit hungrig waren. ???
  951.  
  952.    - Es ist nicht sicher, daß jeder Philosoph nach einer endlich langen
  953.      Zeit essen kann (livelock). Dies kann man verhindern, indem man an
  954.      die einzelnen Philosophen dynamische Prioritäten verteilt, die mit
  955.      der Wartezeit steigen.
  956.  
  957.  
  958.  
  959. @HBVorteile von Semaphoren:
  960.    - mächtiges und flexibles Instrument zur Synchronisation
  961.    - Prozessor wird nicht durch "busy-waiting" unnötig belegt
  962.  
  963. Nachteile:
  964.    - Synchronisation mit Semaphoren ist meist undurchsichtig und
  965.      schwer zu konstruieren.
  966.    - Es kann weder zur Compilezeit noch zur Laufzeit die Plausibilität
  967.      erkannt werden. Man kann keine Schreibfehler (P statt V oder
  968.      umgekehrt, P-Operation auf falsches Semaphor) erkennen.
  969.    - Man sieht nicht, welche V-Operation zu welcher P-Operation gehört.
  970.    - Beweismethoden sind schwer zu entwickeln und anzuwenden.
  971.  
  972. Bemerkung:
  973.    - Semaphor-Operationen sind eher den Assembler-Befehlen zuzuordnen,
  974.      als Konstrukten höherer Programmiersprachen.
  975.  
  976. @HEAnsatz für "Beweise von Semaphor-Operationen"
  977. @HB
  978. Charakteristische Variablen bei Semaphor-Operationen sind
  979.  
  980.   a) @HPnv [s]@HB : Anzahl bisher ausgeführter V-Operationen auf s
  981.   b) @HPnp [s]@HB : Anzahl der begonnenen und vollendeten P-Operationen auf s
  982.   c) @HPna [s]@HB : Anzahl der jemals begonnenen P-Operationen auf s
  983.  
  984. Für die P-Operation gilt:              Für die V-Operation gilt:
  985. @HA
  986. P (s) : { na [s] := na [s] + 1;        V (s) : { nv [s] := nv [s] + 1;
  987.           s := s - 1;                            s := s + 1;
  988.           IF s < 0 THEN Warte (s);               IF s ≤ 0 THEN Warte (s);
  989.           np [s] := np [s] + 1; }              }
  990. @HB
  991. Dabei hat immer folgende Invariante zu stimmen:
  992. @HP
  993.         np [s] = min {na [s], c [s] + nv [s]}   @HBsiehe ⌐Habermann@BS___3¬
  994.  
  995.  
  996.                 @HBweiter mit ⌐Region@BS___3¬
  997. AHBAA #!!# Region
  998. Ein @HPbedingtes kritisches Gebiet@HB wird definiert durch
  999.  
  1000.    @HAREGION V WHEN B DO Si END;@HB
  1001.  
  1002. wobei @HPV@HB  : eine Menge gemeinsam benutzbarer Betriebsmittel ist, die im
  1003.            Vereinbarungsteil mit dem Präfix @HAshared@HB bei der Typ-Angabe
  1004.            dazu gekennzeichnet wurde.
  1005.  
  1006.       @HPB@HB  : ein boolscher Aurdruck / eine Bedingung ist
  1007.            (der Teil "WHEN B" ist optional).
  1008.  
  1009.       @HPSi@HB : Anweisungen sind, die wie in einem kritischen Gebiet ablaufen
  1010.            (Si kann nur ausgeführt werden, wenn ein Prozeß im Besitz
  1011.            von V ist und B true ist):
  1012.  
  1013.  
  1014.  
  1015.  
  1016. @HBEs müssen folgende Forderungen erfüllt sein, damit man von einem
  1017. kritischen Gebiet sprechen kann:
  1018.  
  1019.   1) Während der Bearbeitung der Si kann V nicht an einen anderen
  1020.      ⌐Prozeß@BS1¬ vergeben werden.
  1021.  
  1022.   2) Die in B vorkommenden Variablen können nur in kritischen Gebieten
  1023.      geändert werden.
  1024.  
  1025.   3) Si selbst darf keine region-Anweisung sein, da sonst Deadlocks
  1026.      entstehen können.
  1027.  
  1028.  
  1029.  
  1030.  
  1031.  
  1032.  
  1033.  
  1034. @HEArbeitsweise der region-Anweisung:
  1035. @HB
  1036. Bei der Ausführung der Anweisung wird versucht, die in V aufgelisteten
  1037. ⌐Betriebsmittel@BS1¬ für den Prozeß zu reservieren.
  1038.  
  1039. Können nicht sämtliche in V aufgeführten Betriebsmittel reserviert werden,
  1040. so muß der Prozeß alle bereits belegten Betriebsmittel wieder freigeben
  1041. und später neu gestartet werden.
  1042.  
  1043. Hat die Reservierung funktioniert, so wird der boolsche Ausdruck B ausge-
  1044. wertet:
  1045.  
  1046.   Ist das Ergebnis false, dann müssen wieder alle Betriebsmittel freige-
  1047.   geben werden und der Prozeß wird später neu gestartet.
  1048.  
  1049.   Ist das Ergebnis true, dann werden die Anweisungen Si ausgeführt und
  1050.   anschließend alle Betriebsmittel wieder freigegeben.
  1051.  
  1052. @HEProgrammierung eines kritischen Gebietes:
  1053.  
  1054.   @HAVAR
  1055.   mutex : SHARED T;
  1056.      :
  1057.      :
  1058.      :
  1059.   REGION mutex DO S END;        @HB(* S ist das kritische Gebiet *)
  1060.  
  1061. @HEErzeuger-Verbraucher-Problem
  1062.  
  1063. @HBDie Problemstellung lautet:
  1064.   Es gibt beliebig viele Erzeuger und Verbraucher. Zu jedem Erzeuger i
  1065.   gibt es einen Verbraucher i. Erzeuger und Verbraucher arbeiten auf
  1066.   einem gemeinsamen ⌐Puffer@BS1¬ der Größe N. Der Erzeuger kann nur dann
  1067.   eine Nachricht in den Puffer legen, wenn er einen freien Platz findet.
  1068.   Der Verbraucher i kann nur dann eine Nachricht aus dem Puffer holen,
  1069.   wenn Nachrichten für ihn vorliegen (ni > 0).
  1070. @HELösung 1:@HB
  1071.  
  1072.   @HAVAR
  1073.   v : SHARED RECORD
  1074.         f : Integer;          @HB(* freie Pufferplätze *)@HA
  1075.         n : ARRAY [prozesse] OF Integer;
  1076.                               @HB(* Anzahl Nachrichten für Prozeß *)@HA
  1077.       END;
  1078.  
  1079.   Init (f = N; für alle i: n [i] = 0);
  1080.  
  1081.   Erzeuger_i :    REGION v WHEN f > 0 DO
  1082.                     BEGIN
  1083.                       f := f - 1;
  1084.                       n [i] := n [i] + 1;
  1085.                       "lege Nachricht in den Puffer"
  1086.                     END;
  1087.  
  1088.   @HAVerbraucher_i : REGION v WHEN n [i] > 0 D
  1089.                     BEGIN
  1090.                       f := f + 1;
  1091.                       n [i] := n [i] - 1;
  1092.                       "hole Nachricht aus Puffer"
  1093.                     END;
  1094.  
  1095. @HEAnmerkungen:@HB
  1096.    - Die Unabhängigkeit von der Arbeitsgeschwindigkeit wird hier verletzt.
  1097.  
  1098.      Existiert ein Prozeßpaar mit schnellem Erzeuger aber langsamen Ver-
  1099.      braucher, so kann bald der gesamte Speicher mit Nachrichten für den
  1100.      langsamen Verbraucher belegt sein. Alle anderen Prozesse müssen dann
  1101.      darauf warten, daß dieser wieder Platz schafft, indem er seine Nach-
  1102.      richten aus dem Puffer holt.
  1103.  
  1104.      Alle Prozesse können somit nur mit der Geschwindigkeit des langsamen
  1105.      Verbrauchers arbeiten.
  1106. @HB   - Die Lösung 1 verstößt auch gegen die Forderung, daß ein Prozeß
  1107.      nicht andere Prozesse blockieren darf, wenn er außerhalb des
  1108.      kritischen Gebietes anhält (stirbt).
  1109.  
  1110.      Stirbt ein Verbraucher außerhalb des kritischen Gebietes, so ist
  1111.      irgendwann der Puffer nur noch mit Nachrichten für diesen Prozeß
  1112.      belegt. Andere Erzeuger und Verbraucher können nicht mehr mit dem
  1113.      Puffer arbeiten und werden blockiert.
  1114.  
  1115. Die beiden Verstöße kann man vermeiden, indem man jedem Erzeuger-
  1116. Verbraucher-Paar einen Mindestanteil ri am Puffer garantiert. Stehen
  1117. zusätzlich noch Puffereinheiten zur Verfügung, dürfen diese von allen
  1118. Prozessen benutzt werden.
  1119.  
  1120.  
  1121.  
  1122.  
  1123.  
  1124. @HELösung 2:
  1125.  
  1126.   @HAVAR
  1127.   v : SHARED RECORD
  1128.         f    : Integer        @HB(* zusätzliche freie Pufferplätze *)@HA
  1129.         n, r : ARRAY [prozesse] OF Integer;
  1130.       END;
  1131.  
  1132.   Init (f = N - Σ ri ; für alle i : ri = const, ni = 0)
  1133.                i=0
  1134.  
  1135.   Erzeuger_i :    REGION v WHEN (n [i] < r [i] OR f > 0) DO
  1136.                     BEGIN
  1137.                       n [i] := n [i] + 1;
  1138.                       IF n [i] > r [i] THEN f := f - 1;
  1139.                       "lege Nachricht in den Puffer";
  1140.                     END;
  1141.  
  1142.   @HAVerbraucher_i : REGION v WHEN n [i] > 0 DO
  1143.                     BEGIN
  1144.                       IF n [i] > r [i] THEN f := f + 1;
  1145.                       n [i] := n [i] - 1;
  1146.                       "hole Nachricht aus Puffer";
  1147.                     END;
  1148.  
  1149. @HELeser-Schreiber-Problem@HB
  1150.  
  1151. @HPProblem 1:@HB
  1152. Leser und Schreiber wollen auf ein gemeinsames Betriebsmittel zugreifen,
  1153. zum Beispiel eine Datei. Dabei gelten folgende Regeln:
  1154.  
  1155.   a) Mehrere Leser können gleichzeitig aktiv sein, aber zum gleichen
  1156.      Zeitpunkt kein Schreiber
  1157.   b) Genau ein Schreiber darf aktiv sein, zum gleichen Zeitpunkt kein
  1158.      weiterer Schreiber oder Leser
  1159.   c) Leser werden bevorzugt
  1160.  
  1161. @HELösung 1:
  1162.  
  1163.   @HAVAR
  1164.   rc : SHARED Integer;
  1165.  
  1166.   Init (rc := 0);
  1167.  
  1168.   Reader : REGION rc DO rc := rc + 1 END;
  1169.            "lesen"
  1170.            REGION rc DO rc := rc - 1 END;
  1171.  
  1172.   Writer : REGION rc WHEN rc = 0 DO "schreiben" END;
  1173.  
  1174.  
  1175.  
  1176.  
  1177.  
  1178. @HEAnmerkung:@HB
  1179.  
  1180. Entscheidend ist die Variable rc, die die Leser zählt.
  1181. Auf sie darf nur exklusiv zugegriffen werden, deshalb ist sie das
  1182. eigentliche exklusive Betriebsmittel.
  1183.  
  1184.  
  1185.  
  1186. @HPProblem 2:@HB
  1187.  
  1188.   a) ┐
  1189.      ├ wie bei Problem 1
  1190.   b) ┘
  1191.  
  1192.   c) Schreiber werden bevorzugt
  1193.  
  1194.  
  1195.  
  1196. @HELösung 2:
  1197.  
  1198.   @HAVAR
  1199.   rc, wc : SHARED Integer;
  1200.  
  1201.   Init (rc := 0; wc := 0);
  1202.  
  1203.   Reader : REGION (rc, wc) WHEN wc = 0 DO rc := rc + 1 END;
  1204.            "lesen"
  1205.            REGION (rc) DO rc := rc - 1 END;
  1206.  
  1207.   Writer : REGION (wc) DO wc := wc + 1 END;
  1208.            REGION rc WHEN rc = 0 DO "schreiben" END;
  1209.            REGION (wc) DO wc := wc - 1 END;
  1210.  
  1211.  
  1212.  
  1213.  
  1214. @HEAnmerkung:
  1215. @HB
  1216. Der Writer durchläuft 3 REGION-Anweisungen.
  1217.  
  1218. Zunächst erhöht er wc um 1, so daß danach auf jeden Fall wc > 0 ist
  1219. und sich somit kein reader vordrängeln kann.
  1220.  
  1221. Dann versucht der Writer zu schreiben. Das Schreiben ist in ein
  1222. kritisches Gebiet gelegt, damit garantiert nur ein einziger Writer
  1223. schreiben kann. Durch die Bedingung rc = 0 kann nicht gleichzeitig ein
  1224. Reader lesen.
  1225.  
  1226. In der 3. REGION Anweisung wird wc wieder um 1 erniedrigt.
  1227.  
  1228.  
  1229.  
  1230.  
  1231.  
  1232. @HE5-Philosophen-Problem
  1233. @HB
  1234. Lösung des ⌐5 Philosophen@BS___3¬-Problems unter Verwendung von
  1235. REGION-Anweisungen:
  1236.  
  1237.   @HAVAR
  1238.   Gabel : SHARED ARRAY [0..4] OF T;
  1239.  
  1240.   Philosoph_i : CYCLE
  1241.                   "denken"
  1242.                   REGION (Gabel [i], Gabel [i+1]) DO "essen" END;
  1243.                 END;
  1244. @HEAnmerkungen:@HB
  1245.    - Vorausgesetzt ist, daß die REGION-Implementierung den Zugriff auf
  1246.      einzelne Elemente des SHARED ARRAY erlaubt.
  1247.    - Schwierigkeiten bei Semaphoren, z. B. Test ob Philosoph_i essen darf,
  1248.      sind hier der Implementation überlassen.
  1249.    - Es besteht immer noch das Problem des "Livelocks".
  1250. @HEVorteile bei der Verwendung von REGIONs:@HB
  1251.    - Zur Compilezeit können schon triviale Synchronisationsfehler, wie
  1252.      vergessene Variablen (damit kein synchronisierter Zugriff),
  1253.      Schreibfehler, Schachtelung von REGION-Anweisungen, erkannt und
  1254.      berichtigt werden.
  1255.  
  1256.    - Das REGION-Konzept hat die gleiche Mächtigkeit wie Semaphore
  1257.      (Man kann Semaphore durch REGIONs darstellen.)
  1258.  
  1259. @HENachteil bei der Verwendung von REGIONs:@HB
  1260.    - Das REGION-Konzept ist unökonomisch in Bezug auf die Betriebsmittel,
  1261.      da zu Beginn einer REGION-Anweisung alle Betriebsmittel reserviert
  1262.      werden müssen und diese für die ganze REGION-Zeit belegt sind.
  1263.  
  1264.  
  1265.                weiter mit ⌐Monitore II@BS___3¬
  1266. AHBAA #!!# Monitore II
  1267. Ein Monitor ist eine Sammlung von Daten und Prozeduren. Man kann ihn
  1268. ansehen als ein Programmstück, das man als abstrakten Datentyp des
  1269. ⌐Betriebssystem@BS1¬s auffassen kann.
  1270.  
  1271. Aufbau:
  1272.  
  1273.   @HA<Monitorname> : MONITOR;
  1274.                     BEGIN
  1275.                       <Deklaration lokaler Daten>
  1276.                       <Folge lokaler Prozeduren>
  1277.                       <Initialisierung lokaler Daten>
  1278.                     END;
  1279.  
  1280. @HBDie lokalen Prozeduren eines Monitors können von allen Prozessen
  1281. benutzt werden.
  1282.  
  1283.  
  1284.  
  1285. @HBDer gegenseitige Ausschluß von Prozessen wird bei Monitoren dadurch
  1286. erreicht, daß in einem Monitor immer nur ein einziger Prozeß, also nur
  1287. eine lokale Prozedur, aktiv sein kann.
  1288.  
  1289. Beim Eintritt in einen Monitor haben alle lokalen Daten definierte Werte,
  1290. die auch nicht verloren gehen, wenn der Monitor verlassen wird.
  1291.  
  1292. Ein ⌐Prozeß@BS1¬ (lokale Prozedur) kann mit "wait" in den Wartezustand
  1293. übergehen und kann mit "signal" geweckt werden.
  1294.  
  1295. Welches "wait" zu welchem "signal" gehört, wird über eine Variable vom
  1296. Typ "condition" geregelt.
  1297.  
  1298.   @HAVAR
  1299.   q : condition;
  1300.  
  1301.  
  1302.  
  1303.   @HAq.wait :@HB
  1304.   Das aufgerufene Programm wird angehalten und geht in den Wartezustand
  1305.   über (Warten auf ein Signal der Variablen q).
  1306.   Der beteiligte Monitor ist während der Wartezeit frei für andere
  1307.   Prozesse (der schlafende Prozeß ist ja nicht aktiv).
  1308.   Der schlafende Prozeß besitzt immer noch den Monitor. Er verleiht ihn
  1309.   quasi nur an einen anderen Prozeß.
  1310.   Unterschied zur P-Operation (siehe ⌐Semaphor@BS1¬):
  1311.   Bei P (q) muß man nur warten, wenn q = 0 gilt.
  1312.   Bei q.wait muß der Prozeß immer warten.
  1313.  
  1314.  
  1315.  
  1316.  
  1317.  
  1318.  
  1319.  
  1320.  
  1321.   @HAq.signal :@HB
  1322.   Es wird untersucht, ob es einen Prozeß gibt, der auf q wartet. (Dann
  1323.   gibt die Variable ein Signal.)
  1324.   Kein Prozeß wartet auf q:
  1325.     In diesem Fall ist die signal-Operation wirkungslos und kommt einer
  1326.     leeren Operation gleich.
  1327.   Mindestens ein Prozeß wartet auf q:
  1328.     Es wird ein Prozeß geweckt und sofort aktiviert, dadurch findet er
  1329.     die lokalen Monitordaten so vor, wie sie zum Zeitpunkt der signal-
  1330.     Operation existierten (d. h. der aktivierte Prozeß kann hinter seiner
  1331.     q.wait-Operation weitermachen).
  1332.     Der signalisierende Prozeß befindet sich im selben Monitor wie der
  1333.     wartende und muß deshalb jetzt selbst in den Wartezustand übergehen,
  1334.     da zu einem Zeitpunkt nur ein einziger Prozeß im Monitor aktiv sein
  1335.     kann und das ist in diesem Fall der geweckte.
  1336.   Unterschied zur V-Operation:
  1337.     Nach der V (q)-Operation muß nicht unbedingt (je nach Implementation)
  1338.     ein sofortiger Prozeßwechsel stattfinden, wie es hier der Fall ist.
  1339.   @HAq.queue :@HB
  1340.   Ist eine boolsche Funktion, mit der man abfragen kann, ob es Prozesse
  1341.   gibt, die auf die Variable q vom Typ condition warten.
  1342.   q.queue = true  heißt, es gibt Prozesse, die auf q warten
  1343.   q.queue = false heißt, niemand wartet auf q.
  1344.   Unterschied zu Semaphore:
  1345.   Beim Arbeiten mit Semaphoren ist es nicht möglich, die Größe von
  1346.   Semaphorvariablen abzufragen.
  1347.  
  1348. @HEImplementierung eines binären Semaphors durch einen Monitor
  1349.  
  1350. @HBIndem man angibt, wie Semaphore durch Monitore darstellbar sind,
  1351. kann man zeigen, daß Monitore die gleiche Mächtigkeit besitzen wie
  1352. Semaphore:
  1353.  
  1354.  
  1355.  
  1356.  
  1357. @HAPV: MONITOR;
  1358.          BEGIN
  1359.            VAR
  1360.            Busy : Boolean;      @HB(* true  = ein Prozeß aktiv  *)@HA
  1361.                                 @HB(* false = kein Prozeß aktiv *)@HA
  1362.            NonBusy : Condition;
  1363.            PROCEDURE P;
  1364.              BEGIN
  1365.                IF Busy THEN NonBusy.Wait;
  1366.                Busy := TRUE;
  1367.              END;
  1368.            PROCEDURE V;
  1369.              BEGIN
  1370.                Busy := FALSE;
  1371.                IF NonBusy.Queue THEN NonBusy.Signal;
  1372.              END;
  1373.            Busy := FALSE;
  1374.          END;
  1375.  
  1376. @HEAufruf:
  1377. @HA  PV.P;
  1378.     @HLkritisches Gebiet@HA
  1379.   PV.V;
  1380.  
  1381. @HB    weiter mit  ⌐Monitor-Beispiele@BS___3¬
  1382.     siehe auch: Lexikondefinition ⌐Monitore@BS1¬
  1383.                    ⌐Monitore - Beweis@BS___3¬
  1384.                    ⌐Region@BS___3¬
  1385.                    ⌐Semaphor@BS1¬
  1386.                    ⌐LOCK und UNLOCK@BS___3¬
  1387. AHBAA #!!# Monitor-Beispiele
  1388. @HELösung des Erzeuger-Verbraucher-Problems mit Monitoren
  1389. @HB
  1390. Für die Problemstellung siehe ⌐Erzeuger-Verbraucher@BS___3¬.
  1391. Monitore werden erläutert im Kapitel ⌐Monitore II@BS___3¬.
  1392.  
  1393. Angegeben wird eine Lösung von Hoare, bei der eine faire Verplanung des
  1394. gemeinsam benutzten Puffers stattfindet. Dies wird erreicht, indem beim
  1395. Übergang in den Wartezustand dem Prozeß eine Priorität mitgegeben wird,
  1396. die beim Wecken wartender Prozesse ausgewertet wird. Es wird stets der
  1397. Prozeß mit der kleinsten Priorität geweckt.
  1398.  
  1399. q.wait wird damit erweitert zu q.wait (prio).
  1400.  
  1401.  
  1402.  
  1403.  
  1404.  
  1405.  
  1406. Hoare teilt den Erzeuger-Verbraucher-Paaren keine festen Pufferanteile zu,
  1407. sondern macht folgende Feststellungen für eine faire Verplanung:
  1408.  
  1409.    - Ein nicht aktives Erzeuger-Verbraucher-Paar benötigt keinen Puffer.
  1410.  
  1411.    - Wenn ein Verbraucher wesentlich schneller ist als der Erzeuger, wird
  1412.      das Paar in der Regel nicht mehr als 2 Puffereinheiten belegen.
  1413.  
  1414.    - Zur fairen Verplanung genügt es, demjenigen Prozeß freigewordenen
  1415.      Puffer zuzuteilen, der im Augenblick den wenigsten Platz belegt.
  1416.      Je weniger Pufferplatz ein Prozeß belegt, desto größer soll also
  1417.      seine Priorität sein.
  1418.  
  1419.  
  1420.  
  1421.  
  1422.  
  1423.  
  1424. @HELösung:
  1425. @HA
  1426.   BufferAllocator:
  1427.     MONITOR
  1428.       BEGIN
  1429.         VAR
  1430.         Free : Integer;         @HB(* Anzahl der freien Pufferplätze *)@HA
  1431.         NonEmpty : Condition;
  1432.         Count : ARRAY [1..K] OF Integer;   @HB(* Prioritäten für K   *)@HA
  1433.                                     @HB(* Erzeuger-Verbraucher-Paare *)@HA
  1434.  
  1435.         PROCEDURE Acquire (i : 1..K; VAR Adr : BufferAdr);
  1436.           BEGIN
  1437.             IF Free = 0 THEN NonEmpty.Wait (Count [i]);
  1438.             Free := Free - 1;
  1439.             Count [i] := Count [i] + 1;
  1440.             Adr := ...;        @HB(* lege Nachricht unter Adr ab     *)@HA
  1441.           END;
  1442. @HA
  1443.         PROCEDURE Release (i : 1..K; Adr : Buffer);
  1444.           BEGIN
  1445.             Free := Free + 1;
  1446.             Count [i] := Count [i] - 1;
  1447.             ... := Adr;
  1448.             "hole Nachricht aus dem Puffer"
  1449.             NonEmpty.Signal;
  1450.           END;
  1451.  
  1452.         Free := Speichergröße;         @HB(* Initialisierung *)@HA
  1453.         FOR j := 1 TO K DO             @HB(* "               *)@HA
  1454.           Count [j] := 0;
  1455.  
  1456.  
  1457.  
  1458.  
  1459.  
  1460. @HBAufruf:
  1461.    - Der Erzeuger ruft den Monitor auf mit:
  1462.  
  1463.        @HABufferAllocator.Acquire (i, Adr)@HB
  1464.  
  1465.      wobei i die eigene Prozeßnummer und Adr die Adresse eines freien
  1466.      Pufferplatzes ist.
  1467.  
  1468.    - Der Verbraucher ruft den Monitor auf mit:
  1469.  
  1470.        @HABufferAllocator.Release (i, Adr)@HB
  1471.  
  1472.      wobei i die eigene Prozeßnummer und Adr die Adresse des freizu-
  1473.      gebenden Pufferplatzes ist.
  1474.  
  1475.  
  1476.  
  1477.  
  1478. @HELösung des Leser-Schreiber-Problems mit Monitoren
  1479. @HB
  1480. Zur allgemeinen Problemstellung siehe ⌐Leser-Schreiber@BS___3¬.
  1481.  
  1482. @HPProblemstellung 1@HB
  1483.  
  1484. Der Zugriff von Lesern und Schreibern auf ein gemeinsames ⌐Betriebsmittel@BS1¬,
  1485. zum Beispiel eine Datei, soll nach folgenden Regeln ablaufen:
  1486.  
  1487.   a) Schreiber dürfen nur einzeln (exklusiv) arbeiten.
  1488.  
  1489.   b) Mehrere Leser dürfen gleichzeitig arbeiten.
  1490.  
  1491.   c) Solange es Schreibanwärter gibt, dürfen keine Leser ihre Arbeit
  1492.      beginnen.
  1493.  
  1494.  
  1495.  
  1496. @HELösung 1:
  1497. @HA
  1498.   ReadWrit :
  1499.     MONITOR;
  1500.       BEGIN
  1501.         VAR
  1502.         rc, wc : Integer
  1503.         OkToRead, OkToWrite : Condition;
  1504.  
  1505.         PROCEDURE StartRead;
  1506.           BEGIN
  1507.             IF wc > 0 THEN OkToRead.Wait;
  1508.             rc := rc + 1;
  1509.             OkToRead.Signal;
  1510.           END;
  1511.  
  1512.  
  1513.  
  1514.         @HAPROCEDURE EndRead;
  1515.           BEGIN
  1516.             rc := rc - 1;
  1517.             IF rc = 0 THEN OkToWrite.Signal;
  1518.           END;
  1519.  
  1520.         PROCEDURE StartWrite;
  1521.           BEGIN
  1522.             wc := wc + 1;
  1523.             IF (rc > 0) OR (wc > 1) THEN OkToWrite.Wait;
  1524.           END;
  1525.  
  1526.         PROCEDURE EndWrite;
  1527.           BEGIN
  1528.             wc := wc - 1;
  1529.             IF wc > 0 THEN OkToWrite.Signal
  1530.                       ELSE OkToRead.Signal;
  1531.           END;
  1532. @HA
  1533.         rc := 0;             @HB(* Initialisierung *)@HA
  1534.         wc := 0;             @HB(* "               *)@HA
  1535.       END;
  1536. @HB
  1537. Aufruf:
  1538.    - Der Leser ruft den Monitor auf mit:
  1539.         @HAReadWrite.StartRead;
  1540.         "lesen"
  1541.         ReadWrite.EndRead;@HB
  1542.  
  1543.    - Der Schreiber ruft den Monitor auf mit:
  1544.         @HAReadWrite.StartWrite;
  1545.         "schreiben"
  1546.         ReadWrite.EndWrite;
  1547.  
  1548.  
  1549.  
  1550. @HPProblemstellung 2:
  1551. @HB
  1552. Wie unter Problemstellung 1, jedoch mit neuen Regeln:
  1553.  
  1554.   a) Schreiber dürfen nur einzeln (exklusiv) arbeiten.
  1555.  
  1556.   b) Mehrere Leser dürfen gleichzeitig arbeiten.
  1557.  
  1558.   c) Ein neuer Schreiber darf nicht arbeiten, wenn (mindestens) ein
  1559.      Leser wartet.
  1560.  
  1561.   d) Ein neuer Leser darf nicht arbeiten, wenn (mindestens) ein
  1562.      Schreiber wartet.
  1563.  
  1564.  
  1565.  
  1566.  
  1567.  
  1568. @HELösung 2:
  1569. @HB
  1570. Lediglich die Prozedur EndWrite muß umgeschrieben werden zu:
  1571. @HA
  1572.   PROCEDURE EndWrite;
  1573.     BEGIN
  1574.       wc := wc - 1;
  1575.       IF OkToRead.Queue THEN OkToRead.Signal
  1576.                         ELSE OkToWrite.Signal;
  1577.     END;
  1578. @HB
  1579. Der Aufruf erfolgt wie bei Lösung 1.
  1580.  
  1581.  
  1582.  
  1583.  
  1584.  
  1585.  
  1586. @HELösung des 5 Philosophen Problems mit Monitoren
  1587. @HB
  1588. Zur Problemstellung siehe ⌐5 Philosophen@BS___3¬.
  1589.  
  1590. @HELösung 5 Philosophen
  1591. @HA
  1592.   Philosoph :
  1593.     MONITOR;
  1594.       BEGIN
  1595.         VAR
  1596.         NrForks : ARRAY [0..4] OF 0..2;
  1597.         Fork    : ARRAY [0..4] OF Condition;
  1598.         i       : Integer;
  1599.  
  1600.  
  1601.  
  1602.  
  1603.  
  1604.         PROCEDURE GetForks (i : 0..4);
  1605.           BEGIN
  1606.             IF NrForks [i] < 2 THEN Fork [i].Wait;
  1607.             NrForks [i-1] := NrForks [i-1] - 1;    @HB(* i±1 = i±1 MOD 5 *)
  1608. @HA            NrForks [i+1] := NrForks [i+1] - 1;
  1609.           END;
  1610.  
  1611. @HA        PROCEDURE PutForks (i : 0..4);
  1612.           BEGIN
  1613.             NrForks [i-1] := NrForks [i-1] + 1;
  1614.             NrForks [i+1] := NrForks [i+1] + 1;
  1615.             IF NrForks [i-1] = 2 THEN Fork [i-1].Signal;
  1616.             IF NrForks [i+1] = 2 THEN Fork [i+1].Signal;
  1617.           END;
  1618.  
  1619.         FOR i := 0 TO 4 DO NrForks [i] := 2;
  1620.  
  1621.       END;
  1622. @HBAufruf:
  1623.   Der Philosoph i ruft den Monitor auf mit:
  1624. @HA
  1625.      "denken"
  1626.      Philosoph.GetForks (i);
  1627.      "essen"
  1628.      Philosoph.PutForks (i);
  1629.  
  1630.  
  1631. @HEWeitere Lösungsansätze zur Synchronisation
  1632. @HB
  1633.    - ⌐Guarded Commands@BS2¬
  1634.  
  1635.    - Path-Expressions
  1636.  
  1637.    - Petri-Netze
  1638.  
  1639.  
  1640.  
  1641.  
  1642.        @HBweiter mit ⌐Habermann@BS___3¬
  1643. AHBAA #!!# Habermann
  1644. @HEBeweismethoden für parallele Prozesse
  1645.  
  1646. @HBDie Tests auf Korrektheit bei sequentiellen Programmen sind auf
  1647. parallele Prozesse nicht anwendbar, weil die Bearbeitungsreihenfolge
  1648. unvorhersehbar und nicht reproduzierbar ist. Hier können nur mathe-
  1649. matische Korrektheitsbeweise Sicherheit geben.
  1650.  
  1651. @HEBeweismethode nach Habermann
  1652.  
  1653. @HBDie Beweismethode nach Habermann ist speziell anwendbar auf parallele
  1654. Prozesse, die durch P- und V-Operationen synchronisiert werden. Die
  1655. Grundidee der Methode besteht darin, während des Laufes der Prozesse die
  1656. ⌐Synchronisation@BS1¬svorgänge mitzuzählen. Man arbeitet mit Zählern, die
  1657. lediglich Informationen über die Vergangenheit beinhalten ("history
  1658. variables") und nicht implementiert werden müssen. Zusätzlich stellt man
  1659. eine Invariante auf, die aus diesen Zählern besteht. Sie muß zu jedem
  1660. Zeitpunkt gültig sein. Man testet dann die Verträglichkeit der Zählerzu-
  1661. stände mit der Invariante zum Zweck:
  1662. @HB  - der richtigen Synchronisation
  1663.   - der ⌐Deadlock@BS1¬-Untersuchung
  1664.   - eventuell: Fairness
  1665.  
  1666.  
  1667. @HEZähler und ihre Bedeutung:
  1668.  
  1669.   @HPna [s] @HB: number of attempted P-Operations
  1670.            Anzahl der jemals begonnenen P-Operationen auf ⌐Semaphor@BS1¬ s
  1671.  
  1672.   @HPnp [s] @HB: number of successfull P-Operations
  1673.            Anzahl der begonnenen und vollendeten P-Operationen auf s
  1674.  
  1675.   @HPnv [s] @HB: number of V-Operations
  1676.            Anzahl der ausgeführten V-Operationen auf s
  1677.  
  1678.  
  1679.  
  1680. @HEInvariante und ihre Aussage:
  1681. @HP
  1682.   np [s] = min {na [s]; c [s] + nv [s]}    mit c [s] = Initialwert von s
  1683. @HB
  1684. Die Gleichung besagt:
  1685.  
  1686.   a) Es können nicht mehr Prozesse die P-Operation beendet haben, als sie
  1687.      sie begonnen haben:
  1688.      @HP
  1689.      np [s] <= na [s]
  1690.      @HB
  1691.   b) Es können nicht mehr Prozesse die P-Operation beendet haben als der
  1692.      durch Initialwert und V-Operationen gegebene Wert:
  1693.      @HP
  1694.      np [s] <= c [s] + nv [s]
  1695.      @HB
  1696.  
  1697.  
  1698. @HEBeispiel: Kritisches Gebiet
  1699. @HB
  1700. Ein kritisches Gebiet besteht aus dem Programmstück
  1701.  
  1702. @HA  P (s);
  1703.     Anweisungen
  1704.   V (s);
  1705.  
  1706. @HBmit einem gegebenen Initialwert von s, c [s]. Dieser Initialwert
  1707. gibt die maximal zulässige Anzahl von Prozessen im kritischen Gebiet an.
  1708. Es sei c [s] = 1.
  1709.  
  1710. a) Zu beweisen:
  1711. @HE   Es kann sich höchstens genau ein Prozeß im kritischen Gebiet aufhalten.
  1712.  
  1713. @HBNach Durchlaufen von P (s) und vor der Ausführung von V (s) gilt auf
  1714. Grund der Invariante:
  1715.   @HPnp [s] <= 1 + nv [s]@HB
  1716.  
  1717. @HBdas heißt, das kritische Gebiet kann höchstens einmal mehr betreten
  1718. werden als es verlassen wurde.
  1719.  
  1720. @HBb) Zu beweisen:
  1721. @HE   Deadlockfreiheit
  1722.  
  1723. @HBEin Deadlock ist aufgetreten, wenn Prozesse am Betreten des
  1724. kritischen Gebiets gehindert werden, obwohl kein Prozeß im kritischen
  1725. Gebiet ist.
  1726.  
  1727.   Annahme: Es gibt wartende Prozesse.              @HPnp [s] < na [s]@HB
  1728.   Aus der Invariante folgt demnach                 @HPnp [s] = 1 + nv [s]@HB
  1729.  
  1730.   Wenn aber niemand im kritischen Gebiet ist,
  1731.   dann muß es genau so oft verlassen wie           @HPnp [s] = nv [s]@HB
  1732.   betreten worden sein.
  1733.  
  1734. @HB  Man erhält also einen Widerspruch, was besagt,
  1735.   daß die Annahme falsch ist.
  1736.  
  1737. @HEBeispiel: Erzeuger-Verbraucher-Problem
  1738. @HB
  1739. Zur allgemeinen Problemstellung siehe ⌐Erzeuger-Verbraucher@BS___3¬.
  1740. @HA
  1741.   CONST
  1742.   BufSize = ...;
  1743.  
  1744.   VAR
  1745.   Leer, Voll : Semaphor;
  1746.   Puffer : ARRAY [0..BufSize - 1] OF Info;
  1747.   ex : Integer;                @HB(* Erzeuger-Index    *)@HA
  1748.   vx : Integer;                @HB(* Verbraucher-Index *)@HA
  1749.  
  1750.  
  1751.  
  1752. @HA  BEGIN
  1753.     ex := 0;        @HB(* ex + 1 = ex + 1 MOD BufSize *)@HA
  1754.     vx := 0;        @HB(* vx + 1 = vx + 1 MOD BufSize *)@HA
  1755.     Voll := 0;
  1756.     PARBEGIN
  1757.       BEGIN @HB(* Erzeuger *)@HA             BEGIN @HB(* Verbraucher *)@HA
  1758.         "erzeuge Blabla";                P (Voll);
  1759.         P (Leer);                        "hole Blabla aus Puffer [vx]";
  1760.      @HJα@HA  Puffer [ex] := Blabla;        @HJß@HA  vx := vx + 1;
  1761.         ex := ex + 1;                    V (Leer);
  1762.         V (Voll);                        "verarbeite Blabla";
  1763.       END;                             END;
  1764.     PAREND;
  1765.   END;
  1766.  
  1767.  
  1768.  
  1769.  
  1770. @HBGehen wir im folgenden von 1 Erzeuger und 1 Verbraucher aus.
  1771.  
  1772.   a) Zu beweisen:
  1773.      Wenn beide Prozesse gleichzeitig auf den Puffer zugreifen, dann muß
  1774.      garantiert sein, daß sie nicht beide auf das gleiche Pufferelement
  1775.      zugreifen.
  1776.  
  1777.      Ein Parallelbetrieb ist also nur dann möglich, wenn BufSize ≥ 2 ist.
  1778.      Ein gleichzeitiger Zugriff auf den Puffer ist dann möglich, wenn sich
  1779.      der Erzeuger bei Marke @HJα@HB und der Verbraucher bei Marke @HJß@HB
  1780.      befindet.
  1781.  
  1782.      Zugriff auf den Puffer bei @HJα@HB:
  1783.        dann gilt für den Erzeuger   : @HLnp [Leer] = nv [Voll] + 1       @HJ1@HB
  1784.        für die Invariante gilt hier : @HLnp [Leer] ≤ BufSize + nv [Leer] @HJ2@HB
  1785.                                       mit c [Leer] = BufSize
  1786.  
  1787.  
  1788. @HB     Zugriff auf den Puffer bei @HJß@HB:
  1789.        dann gilt für den Verbraucher: @HLnp [Voll] = nv [Leer] + 1       @HJ3@HB
  1790.        für die Invariante gilt hier : @HLnp [Voll] ≤    0    + nv [Voll] @HJ4@HB
  1791.                                       mit c [Voll] = 0
  1792.  
  1793.      Wenn beide Prozesse auf das selbe Pufferelement zugreifen, muß gelten 
  1794.  
  1795.                       @HLex = vx@HB
  1796.  
  1797.      Beim Start gilt: @HLex = vx = 0@HB
  1798.  
  1799.      Die Anzahl der Änderungen der beiden Variablen beträgt, wenn die
  1800.      beiden Prozesse sich gerade bei @HJα@HB bzw. @HJß@HB befinden:
  1801. @HL
  1802.        Anzahl Änderungen von ex = np [Leer] - 1
  1803.                                 = np [Voll]                           @HJ5@HL
  1804.        Anzahl Änderungen von vx = np [Voll] - 1
  1805.                                 = np [Leer]                           @HJ6@HB
  1806. @HB     Mit Gleichung @HJ4      @HLnp [Voll] ≤ nv [Voll]
  1807. @HB     und Gleichung @HJ2      @HLnp [Voll] = nv [Leer] + 1
  1808. @HB     erhält man
  1809. @HL                      nv [Leer] + 1 ≤ nv [Voll]
  1810. @HB     bzw. @HL                        1 ≤ nv [Voll] - nv [Leer]
  1811. @HB     und mit Gleichung @HJ5@HB und @HJ6@HL    1 ≤ ex - vx
  1812. @HB
  1813.      Man sieht, daß ex um mindestens eine Einheit vs vorausgeht.
  1814.  
  1815.      Andererseits gilt:   @HLnv [Voll] = np [Leer] - 1         @HBaus @HJ1@HB
  1816.                   und     @HLnp [Leer] ≤ BufSize + nv [Leer]   @HBaus @HJ2@HB
  1817.  
  1818.      woraus man erhält:   @HLnv [Voll] ≤ BufSize + nv [Leer] - 1@HB
  1819.                   bzw.    @HLnv [Voll] - nv [Leer] ≤ BufSize - 1
  1820.                             ex      -   vx      ≤ BufSize - 1
  1821. @HB
  1822.      Das bedeutet, ex kann vx nicht einholen.     q. e. d.
  1823.  
  1824. @HB  b) Zu beweisen:
  1825.      Deadlockfreiheit
  1826.  
  1827.      Wenn ein Deadlock auftritt,
  1828.      dann muß gelten:            @HL            np < na
  1829. @HB     Beim Erzeuger gilt für
  1830.      die Invariante:             @HL     np [Leer] = BufSize + nv [Leer]
  1831. @HB     Beim Verbraucher gilt für
  1832.      die Invariante:             @HL     np [Voll] = nv [Voll]
  1833. @HB
  1834.      Wenn kein Prozeß arbeitet, haben genau so viele Prozesse
  1835.      ihre Arbeit beendet wie begonnen
  1836.        Beim Erzeuger gilt daher   :   @HLnp [Leer] = nv [Leer]@HB
  1837.        Beim Verbraucher gilt daher:   @HLnp [Voll] = nv [Voll]@HB
  1838.  
  1839.      Da BufSize > 0 ist, ergibt sich ein Widerspruch. Die Annahme, daß
  1840.      ein Deadlock auftreten könnte, ist also falsch.
  1841.  
  1842. @HEAnmerkung:
  1843.  
  1844. @HBBedingte P- und V-Operationen sind mit dieser Methode schwierig
  1845. zu beweisen.
  1846.  
  1847.  
  1848.          weiter mit ⌐Owicki / Gries@BS___3¬
  1849. AHBAA #!!# Owicki / Gries
  1850. @HBDie Tests auf Korrektheit bei sequentiellen Programmen sind auf
  1851. parallele Prozesse nicht anwendbar, weil die Bearbeitungsreihenfolge
  1852. unvorhersehbar und nicht reproduzierbar ist. Hier können nur mathe-
  1853. matische Korrektheitsbeweise Sicherheit geben.
  1854.  
  1855. @HEBeweismethode nach Owicki / Gries
  1856.  
  1857. @HBDiese Beweismethode geht von der von Hoare entwickelten Notation:
  1858.  
  1859. @HA  {precondition} statement {postcondition}
  1860.  
  1861. @HBfür sequentielle Programme aus. Dabei ist die Grundidee, Programm-
  1862. folgen in elementare Operationen zu zerlegen, diese im einzelnen durch
  1863. bestimmte Beweisregeln zu verifizieren und sie dann wieder zu größeren
  1864. Einheiten zusammenzusetzen.
  1865.  
  1866.  
  1867.  
  1868.  
  1869.                  @HAa, b, c
  1870. @HBHoare Notation: @HA─────────
  1871.                  @HA   d
  1872.  
  1873. @HBbedeutet: wenn a, b und c wahr sind, dann ist auch d wahr.
  1874.  
  1875.                                       @HA{P AND B} S {P}
  1876. @HBBeispiel für WHILE-Statement: @HA────────────────────────────────
  1877.                                @HA{P} WHILE B DO S {P AND NOT B}
  1878.  
  1879.  
  1880.  
  1881.  
  1882.  
  1883.  
  1884.  
  1885.  
  1886. @HBUm Beweismethoden entwickeln zu können haben Owicki / Gries zwei
  1887. Sprachelemente definiert:
  1888.  
  1889.   a) COBEGIN, COEND was dem PARBEGIN, PAREND entspricht
  1890.  
  1891.   b) AWAIT B THEN S                 (* Ähnlichkeit mit ⌐Region@BS___3¬ *)
  1892.      wobei B Boolscher Ausdruck und
  1893.            S eine Anweisung, die weder COBEGIN noch AWAIT enthält.
  1894.  
  1895. Wenn ein Prozeß ein AWAIT-Statement ausführen will, dann wird er so
  1896. lange zurückgestellt, bis B wahr ist. Dann wird S wie eine unteilbare
  1897. Operation ausgeführt. Nach dem Ende von S wird die Parallelarbeit
  1898. fortgesetzt.
  1899.  
  1900.  
  1901.  
  1902.  
  1903.  
  1904. @HBDie Beweisregeln für die beiden Sprachelemente lauten:
  1905.  
  1906.   a) COBEGIN
  1907. @HA                       {Pi} Si {Qi}        für i = 1..n
  1908.         ───────────────────────────────────────────────────────────
  1909.          {P1, ..., Pn} COBEGIN S1; S2; ...; Sn COEND {Q1, ..., Qn}
  1910.  
  1911. @HB     Da S1, S2, ..., Sn parallel arbeiten dürfen, müssen die
  1912.      Zusicherungen (Pi, Qi) unabhängig voneinander sein.
  1913.  
  1914.   b) AWAIT
  1915. @HA            {P AND B} S {Qi}
  1916.         ────────────────────────
  1917.          {P} AWAIT B THEN S {Q}
  1918.  
  1919.      @HBDas AWAIT-Statement kann nur betreten werden, wenn B wahr ist.
  1920.      Nach dem Verlassen des Statements kann über B keine Aussage gemacht
  1921.      werden.
  1922.  
  1923. @HEBeispiel:
  1924.  
  1925. @HBZu beweisen ist folgendes Programmstück, das als Ergebnis x = 3
  1926. liefert:
  1927.  
  1928. @HA     x := 0;
  1929.      COBEGIN
  1930.        AWAIT TRUE THEN x := x + 1;
  1931.        AWAIT TRUE THEN x := x + 2;
  1932.      COEND;
  1933.  
  1934.  
  1935.  
  1936.  
  1937.  
  1938.  
  1939.  
  1940.  
  1941.      @HAx := 0;
  1942.      @HB{x = 0}
  1943.      @HACOBEGIN @HB{x = 0}
  1944.        @HB{x = 0 OR x = 2}
  1945.        @HAAWAIT TRUE THEN x := x + 1;
  1946.        @HB{x = 1 OR x = 3}
  1947.  
  1948.        @HB{x = 0 OR x = 1}
  1949.        @HAAWAIT TRUE THEN x := x + 2;
  1950.        @HB{x = 2 OR x = 3}
  1951.      @HACOEND;
  1952.      @HB{(x = 1 OR x = 3) AND (x = 2 OR x = 3)} ==> {x = 3}
  1953.  
  1954. @HBFür dieses triviale Beispiel ist die Beweismethode geeignet,
  1955. aber sie ist nicht realistisch für umfangreichere Programme.
  1956.  
  1957.  
  1958.  
  1959. @HBEin wenig kann man sich helfen, indem man Hilfsvariablen einführt.
  1960. Dabei muß man aber beachten:
  1961.  
  1962.   1. Hilfsvariablen h dürfen nur in Zuweisungen der Form h := expr
  1963.      vorkommen, wobei expr eine Expresssion ist, in der kein h
  1964.      vorkommen darf.
  1965.  
  1966.   2. hi darf nur in Statement Si vorkommen
  1967.  
  1968.   3. Das Originalprogramm muß nach dem Entfernen der Hilfsvariablen
  1969.      erhalten bleiben.
  1970.  
  1971.  
  1972.  
  1973.  
  1974.  
  1975.  
  1976. @HBDas obige Beispiel lautet dann:
  1977.  
  1978.      @HAx := 0;
  1979.      h1 := 0;
  1980.      h2 := 0;
  1981.      COBEGIN
  1982.        AWAIT TRUE THEN
  1983.          BEGIN
  1984.            x := x + 1;
  1985.            h1 := 1;
  1986.          END;
  1987.        AWAIT TRUE THEN
  1988.          BEGIN
  1989.            x := x + 2;
  1990.            h2 := 2;
  1991.          END;
  1992.      COEND;
  1993.      @HBmit {x = h1 + h2} als Invariante
  1994. @HBDie Beweismethode von Gries und Owicki erlaubt es auch, Semaphor-
  1995. Konstruktionen zu beweisen. Dazu muß man allerdings die P- und
  1996. V-Ausdrücke in das AWAIT-Statement übersetzen.
  1997.  
  1998. @HBDie ursprüngliche Definition für Semaphore:
  1999.  
  2000. @HA  P (s) ::= { IF s = 0 THEN Warte (s);
  2001.               s := s - 1; }
  2002.  
  2003.   V (s) ::= { s := s + 1;
  2004.               IF "jemand wartet auf s" THEN Wecke (s); }
  2005.  
  2006. @HBwird dann zu:
  2007.  
  2008. @HA  P (s) ::= AWAIT s > 0 THEN s := s - 1;
  2009.  
  2010.   V (s) ::= AWAIT TRUE THEN s := s + 1;
  2011.  
  2012. @HEErweiterung der Beweismethode
  2013. @HBOwicki und Gries haben bei ihrer Erweiterung folgende zwei Statements
  2014. entwickelt:
  2015.  
  2016.   a) RESOURCE r1 (SHARED VARIABLE LIST), ..., rm (SHARED VARIABLE LIST):
  2017.        COBEGIN S1 ||...|| Sn COEND
  2018.  
  2019.   b) WITH r WHEN B DO S                  (* critical section statement *)
  2020.      (zum Vergleich: REGION V THEN B DO S)
  2021.      wobei r eine Menge von Betriebsmitteln (shared variables),
  2022.            B Boolean Expression und
  2023.            S Statement, das die Variablen aus r verwendet, ist.
  2024.  
  2025. Wenn ein Prozeß versucht das Critical-Section-Statement auszuführen,
  2026. wird er solange zurückgestellt, bis B wahr ist und r nicht von einem
  2027. anderen Prozeß verwendet wird. Ist B wahr und der Prozeß besitzt r, dann
  2028. wird S ausgeführt. Nach dem Ende von S ist r wieder frei für andere
  2029. Prozesse.
  2030. @HBDas Statement kann nur innerhalb von parallelen Prozeßabläufen vor-
  2031. kommen. Für das gleiche r ist eine Verschachtelung des Statements nicht
  2032. erlaubt.
  2033.  
  2034. Durch die folgenden Syntaxregeln wird erreicht, daß alle shared
  2035. variables, wegen denen es zu Synchronisationsproblemen kommen kann,
  2036. durch das kritische Gebiet (critical section statement) geschützt sind.
  2037.  
  2038.   a) Wenn eine Variable x zur Resource r gehört, dann darf x nur in einem
  2039.      kritischen Gebiet für r vorkommen.
  2040.  
  2041.   b) Wenn x in einem Statement S verändert wird, dann muß es zu einer
  2042.      Resource r gehören.
  2043.  
  2044. Diese beiden Regeln vereinfachen die Korrektheitsbeweise von Programmen
  2045. und sie sind vom Compiler überprüfbar.
  2046.  
  2047.  
  2048.  
  2049. @HBFür die Betriebsmittel r wurde eine Invariante I (r) definiert. Sie
  2050. muß wahr sein, wenn die parallele Abarbeitung der Prozesse beginnt und
  2051. im weiteren immer dann gültig, wenn kein kritisches Gebiet (critical
  2052. section statement) für r ausgeführt ist (das heißt vor dem Betreten des
  2053. kritischen Gebietes für r stehen die Betriebsmittel r zur Verfügung und
  2054. nach dem Verlassen des kritischen Gebiets für r werden alle Betriebs-
  2055. mittel die zu r gehören wieder freigegeben).
  2056.  
  2057.  
  2058.  
  2059.  
  2060.  
  2061.  
  2062.  
  2063.  
  2064.  
  2065.  
  2066. @HBDie Invariante wird bei den beiden Beweisaxiomen verwendet:
  2067.  
  2068.   a) Axiom für paralleles Arbeiten
  2069.  
  2070. @HA                     für alle i:     {Pi} Si {Qi}
  2071.         ───────────────────────────────────────────────────────────
  2072.                {I (r) AND P1 AND ... AND Pn} RESOURCE r:
  2073.          COBEGIN S1 ||...|| Sn COEND {I (r) AND Q1 AND ... AND Qn}
  2074.  
  2075. @HB  b) Axiom für kritisches Gebiet
  2076.  
  2077. @HA           {I (r) AND P AND B} S {I (r) AND Q}
  2078.           ─────────────────────────────────────
  2079.                {P} WITH r WHEN B DO S {Q}
  2080.  
  2081.  
  2082.     @HBweiter mit ⌐Monitore - Beweis@BS___3¬
  2083.     @HBsiehe auch: Beweismethode nach ⌐Habermann@BS___3¬
  2084. AHBAA #!!# Monitore - Beweis
  2085. @HEBeweismethoden für Monitore (nach Hoare)
  2086. @HBFür Monitore wurden folgende Beweisregeln aufgestellt:
  2087.  
  2088.   1. {true}      Initialisierung   {J AND E}
  2089.   2. {J AND E}   jede Prozedur     {J AND E}
  2090.   3. {J AND E}   cond.wait         {J AND B}
  2091.   4. {J AND B}   cond.signal       {J AND E}
  2092.  
  2093. Dabei bedeutet
  2094.  
  2095. @HPJ@HB: Eine Invariante, die die Korrektheit der Monitordaten zusichern soll.
  2096. @HPB@HB: Eine Zusicherung, daß für jede cond-Variable eine signal-Operation
  2097.    ausgeführt wird. B beschreibt die Bedingungen, die für das Wecken
  2098.    Voraussetzung sind.
  2099. @HPE@HB: Eine Zusicherung, daß unnötiges Warten nicht erlaubt ist, das heißt
  2100.    daß nach einer signal-Operation sofort ein Prozeß geweckt wird
  2101.    (wichtig, weil dann der geweckte Prozeß genau die Daten vorfindet, wie
  2102.    sie bei der signal-Operation gelten).
  2103. @HBMan kann sich die Arbeit des Beweises erleichtern, indem man auch hier
  2104. "history-variables" verwendet. (Sie dienen nur der Beschreibung und
  2105. werden nicht implementiert.)
  2106.  
  2107. Als nächstes sucht man sich eine Invariante und zeigt, daß sie
  2108. tatsächlich gilt.
  2109.  
  2110. @HEBeispiel: Erzeuger-Verbraucher Problem
  2111.  
  2112. @HBHistory-Variables:
  2113.   @HPA@HB : enthält alle Infos, die jemals in den Puffer gelegt wurden
  2114.   @HPR@HB : enthält alle Infos, die jemals aus dem Puffer entfernt wurden
  2115.   @HPS@HB : enthält alle Infos, die im Puffer liegen (Differenz von A und R)
  2116.  
  2117. Invariante:
  2118.  
  2119.    @HPA = R konkat S@HB              mit konkat = Verkettung, Konkatenation
  2120.  
  2121. @HEDer Monitor mit History-Variables:
  2122.  
  2123. @HABoundedBuffer : MONITOR
  2124.   BEGIN
  2125.     VAR
  2126.     A, R : ARRAY [1..unendlich] OF Message;
  2127.     S : ARRAY [1..BufSize] OF Message;
  2128.     NotFull, NotEmpty : Condition;
  2129.  
  2130.     PROCEDURE Append (x : Message);
  2131.       BEGIN
  2132.         IF S.Lenght = BuffSize THEN NotFull.Wait;
  2133.         A := A konkat <x>;
  2134.         S := S konkat <X>;
  2135.         IF NotEmpty.Queue THEN NotEmpty.Signal;
  2136.       END;
  2137.  
  2138.  
  2139.     PROCEDURE Remove (x : Message);
  2140.       BEGIN
  2141.         IF S.Length = 0 THEN NotEmpty.Wait;
  2142.         x := S.First;
  2143.         S := S.Rest;
  2144.         R := R konkat <x>;
  2145.         IF NotFull.Queue THEN NotFull.Signal;
  2146.       END;
  2147.  
  2148.     @HB(* Initialisierung: *)@HA
  2149.     A := R := S := <>        @HB(* empty *)@HA
  2150.   END;
  2151.  
  2152. @HBS.Append (x) bedeutet S := S konkat <x>
  2153. S.Remove (x) bedeutet x := S.First; S := S.Reset
  2154.  
  2155.  
  2156.  
  2157.  
  2158. @HBInvariante: A = R konkat S
  2159.  
  2160. @HEBeweis der append-Prozedur:
  2161.  
  2162.   @HB{A = R konkat S} ==> {A konkat <x> = R konkat S konkat <x>}
  2163.   @HAA := A konkat <x>;
  2164.   @HB{A = R konkat S konkat <x>}
  2165.   @HAS := S konkat <x>;
  2166.   @HB{A = R konkat S}
  2167.  
  2168.  
  2169.  
  2170.  
  2171.  
  2172.  
  2173.  
  2174.  
  2175. @HEBeweis der remove-Prozedur:
  2176.  
  2177.   @HB{A = R konkat S AND S ist nicht leer} ==>
  2178.   {A = R konkat S.First konkat S.Rest}
  2179.   @HAx := S.First;
  2180.   @HB{A = R konkat <x> konkat S.Rest}
  2181.   @HAS := S.Rest;
  2182.   @HB{A = R konkat <x> konkat S}
  2183.   @HAR := R konkat <x>;
  2184.   @HB{A = R konkat S}
  2185.  
  2186. @HBDie Initialisierung sowie die Funktionsweise von signal und wait
  2187. muß noch bewiesen werden. Dann hat man gezeigt, daß A = R konkat S
  2188. tatsächlich invariant ist.
  2189.  
  2190.  
  2191.  
  2192.  
  2193. @HEBeweis der Initialisierung:
  2194.  
  2195.   @HB{true} ==> {<> = <> konkat <>}
  2196.   @HAA := <>;
  2197.   @HB{<> = <> konkat <> AND A = <>} ==> {A = <> konkat <>}
  2198.   @HAR := <>;
  2199.   @HB{A  = <> konkat <> AND R = <>} ==> {A = R  konkat <>}
  2200.   @HAS := <>;
  2201.   @HB{A  =  R konkat <> AND S = <>} ==> {A = R  konkat S }
  2202.  
  2203.  
  2204. @HB     weiter mit: Deadlocks, ⌐Betriebsmittel II@BS___4¬
  2205.      siehe auch: ⌐Monitore@BS1¬
  2206.                  ⌐Monitore II@BS___3¬
  2207.