3.2.11.3 Semaphore

[gesichtete Version][gesichtete Version]
Keine Bearbeitungszusammenfassung
K (nicht geschlossene loop_task tags)
 
(93 dazwischenliegende Versionen von 6 Benutzern werden nicht angezeigt)
Zeile 1: Zeile 1:
<p>
<p>
{{#index:Semaphore|Dijkstra|Edsger Wybe Dijkstra}}
<loop_index id="5fa9787b5e52e">Semaphore|Dijkstra|Edsger Wybe Dijkstra</loop_index>
Der niederländische Informatiker [http://de.wikipedia.org/wiki/Edsger_W._Dijkstra Edsger Wybe Dijkstra] hat das Semaphor-Konzept in den 1960er-Jahren entwickelt, und in seinem Artikel [http://alexandria.tue.nl/extra1/dictaten/wiski/753894.pdf Co-Operating Sequential Processes] vorgestellt. Auf Wikipedia findet sich ein [http://de.wikipedia.org/wiki/Semaphor_(Informatik)#Namensherkunft Hinweis zur Namensherkunft] des Begriffs ''Semaphor''.
Der niederländische Informatiker [http://de.wikipedia.org/wiki/Edsger_W._Dijkstra Edsger Wybe Dijkstra] hat das Semaphor-Konzept in den 1960er-Jahren entwickelt, und in seinem Artikel [https://pure.tue.nl/ws/portalfiles/portal/4279816/344354178746665.pdf Co-Operating Sequential Processes] vorgestellt. Auf Wikipedia findet sich ein [http://de.wikipedia.org/wiki/Semaphor_(Informatik)#Namensherkunft Hinweis zur Namensherkunft] des Begriffs ''Semaphor''.
</p>
 
<p>
Wie im weiteren Verlauf dieses Abschnitts noch zu sehen sein wird, können mit Hilfe des Semaphor-Konzepts eine Reihe von Problemen der Prozess-Synchronisation gelöst werden. Als großer Vorteil der Semaphore wird noch zu erkennen sein, dass sie dabei auf [[aktives Warten]] verzichten, und somit '''nicht''' den Nachteil der ''Verschwendung von CPU-Zeit'' haben.
</p>
 
<p>
Zunächst einige Definitionen:
</p>
</p>


<br />
<br />
==== Definition: Semaphor ====
== Definition: Semaphor ==
<p>
<p>
{{#index:Semaphor|P()-Operation|up()-Operation|V()-Operation|down()-Operation}}
<loop_index id="5fa9787b5e53a">Semaphor|P()-Operation|up()-Operation|V()-Operation|down()-Operation</loop_index>
<loop_area type="definition">
<loop_area type="definition">
<p>
<p>
Unter einem '''Semaphor''' versteht man eine Datenstruktur, welche einen ganzzahligen Zähler, sowie eine Warteschlange bereitstellt. Zusätzlich sind zwei [[TSL-Befehl#Definition:_Atomare_Aktion|atomare Operationen]] <span style="font-family:Courier">P()</span> und <span style="font-family:Courier">V()</span> auf diese Datenstruktur definiert.
Unter einem '''Semaphor''' versteht man eine Datenstruktur, welche einen ganzzahligen Zähler, sowie eine Warteschlange bereitstellt. Zusätzlich sind zwei [[Das_Problem_des_ungünstigsten_Moments#Definition:_Atomare_Aktion|atomare Operationen]] &nbsp;<span style="font-family:Courier">P()</span>&nbsp; und &nbsp;<span style="font-family:Courier">V()</span>&nbsp; auf diese Datenstruktur definiert.
</p>
</p>
</loop_area>
</loop_area>
</p>
</p>


<br />
<p>
Ein ''ganzzahliger Zähler'' ist in der Programmierung beispielsweise eine einfache [http://de.wikipedia.org/wiki/Integer_%28Datentyp%29 Integer]-Variable. Diese kann negative oder positive ganzzahlige Werte annehmen. Der ganzzahlige Zähler einer Semaphore hingegen kann keine negativen Werte annehmen.
</p>
<p>
<p>
Ein ''ganzzahliger Zähler'' ist in der Programmierung beispielsweise eine einfache [http://de.wikipedia.org/wiki/Integer_%28Datentyp%29 Integer]-Variable. Eine ''[http://de.wikipedia.org/wiki/Warteschlange_%28Datenstruktur%29 Warteschlange]'' ist eine klassische Datenstruktur in der Informatik, die nach dem [http://de.wikipedia.org/wiki/First_In_%E2%80%93_First_Out FIFO-Prinzip (First In, First Out)] arbeitet. Sie dient hier zur geordneten Aufnahme von Prozessen.
Eine ''[http://de.wikipedia.org/wiki/Warteschlange_%28Datenstruktur%29 Warteschlange]'' ist eine klassische Datenstruktur in der Informatik, die nach dem [http://de.wikipedia.org/wiki/First_In_%E2%80%93_First_Out FIFO-Prinzip (First In, First Out)] arbeitet. Sie dient hier zur geordneten Aufnahme von Prozessen.
</p>
</p>
<p>
<p>
Zeile 23: Zeile 35:


<br />
<br />
==== Arbeitsweise eines Semaphors ====
 
== Definition: Binärer Semaphor ==
<p>
<loop_index id="5fa9787b5e542">Semaphor, binär|Binärer Semaphor</loop_index>
<loop_area type="definition">
<p>
<p>
{{#index:Semaphor, Arbeitsweise|Arbeitsweise Semaphor|binärer Semaphor|Semaphor, binär}}
Unter einem '''binären Semaphor''' versteht man einen Semaphor, dessen ganzzahliger Zähler nur die Werte 0 oder 1 annehmen kann.
Zunächst wird eine Instanz '''<span style="font-family:Courier">s</span>''' eines Semaphors erstellt, diese steht mehreren Prozessen zur Synchronisation zur Verfügung.
</p>
</p>
<p>
</loop_area>
Die Integer-Variable von <span style="font-family:Courier">s</span> wird mit einem Wert größergleich 1 initialisiert. Bei einem Wert von genau 1 spricht man von einem '''binären Semaphor''', bei Werten größer als 1 von einem '''Zählsemaphor'''. Beide Typen haben i.d.R. unterschiedliche Einsatzzwecke.
</p>
</p>


<br />
==== Zweck eines binären Semaphors ====
<p>
<p>
{{#index:mutal exclusion|gegenseitiger Ausschluss|wechselseitiger Ausschluss}}
Ein binärer Semaphor besitzt gemäß seiner Definition ebenso eine Warteschlange und auch die auf ihm operierenden <span style="font-family:Courier">P()</span>- und <span style="font-family:Courier">V()</span>-Operationen.
Ein binärer Semaphor ist geeignet, um [[Kritischer Abschnitt|kritische Abschnitte]] vor gleichzeitigem Betreten zu sichern. Man spricht in diesem Zusammenhang von einem ''wechselseitigen Ausschluss'' (auf englisch: ''mutal exclusion'') der beteiligten Prozesse.
</p>
</p>


<br />
<br />
==== Definition: Mutex ====
== Definition: P()-Operation eines Semaphors ==
<p>
<p>
{{#index:Mutex}}
<loop_index id="5fa9787b5e549">Semaphor, P()-Operation</loop_index><loop_index id="5fa978c09c110">P()-Operation Semaphor</loop_index>
<loop_area type="definition">
<loop_area type="definition">
<p>
<p>
Unter einem '''Mutex''' (als Abkürzung für '''MUTal EXclusion''', auf deutsch: '''gegenseitiger Ausschluss''') versteht man einen binären Semaphor.
Die <span style="font-family:Courier">P()</span>-Operation eines Semaphors ist als [[Das_Problem_des_ungünstigsten_Moments#Definition:_Atomare_Aktion|atomare Operation]] wie folgt definiert:
</p>
<p>
* Hat die Zählervariable einen positiven Wert (>0), dann verringere den Wert der Zählvariablen um 1.
* Wenn die Zählvariable den Wert 0 hat, dann blockiert die <span style="font-family:Courier">P()</span>-Operation den aufrufenden Prozess und fügt ihn an das Ende ihrer Warteschlange hinzu.
</p>
</p>
</loop_area>
</loop_area>
</p>
<p>
Mit "blockieren" ist hier das Ändern des [[Prozesszustände|Prozesszustands]] des die <span style="font-family:Courier">P()</span>-Operation aufrufenden Prozesses in den [[Prozesszustände|Zustand "Blockiert"]] gemeint.
</p>
</p>


<br />
<br />
==== Zweck eines Zählsemaphors ====
 
== Definition: V()-Operation eines Semaphors ==
<p>
<p>
Ein Zählsemaphor ist geeignet, um eine begrenzte Anzahl von "Irgendwas" zu verwalten. Dieses "Irgendwas" kann entsprechend seiner Anzahl genutzt werden, aber nicht darüber hinaus. Der Zugriff auf "Irgendwas" stellt deshalb einen [[Kritischer Abschnitt|kritischen Abschnitt]] dar, und muss geschützt werden.
<loop_index id="5fa9787b5e54f">Semaphor, V()-Operation</loop_index><loop_index id="5fa9787b9a2d0">V()-Operation Semaphor</loop_index>
</p>
<loop_area type="definition">
<p>
<p>
<loop_area type="example">
Die <span style="font-family:Courier">V()</span>-Operation eines Semaphors ist als [[Das_Problem_des_ungünstigsten_Moments#Definition:_Atomare_Aktion|atomare Operation]] wie folgt definiert:
<p>
In einer Bibliothek stehen beispielsweise fünf Ausgaben des Buchs <cite>Tanenbaum+2009</cite>. Damit können maximal fünf Personen dieses Buch ausleihen. Das "Irgendwas" ist in diesem Beispiel das Buch. Eine Person repräsentiert einen Prozess.
</p>
</p>
<p>
<p>
Solange noch Ausgaben des Buchs in der Bibliothek vorhanden sind, kann es ausgeliehen werden. Sind alle Ausgaben verliehen, so muss die nächste ausleihwillige Person so lange warten, bis (mindestens) ein Buch abgegeben wurde, der Ausleihvorgang dafür also beendet wurde.
* Wenn die Warteschlange nicht leer ist, dann entblockiere den ersten Prozess der Warteschlange.
* Ist die Warteschlange leer, dann erhöhe den Wert der Zählervariable um 1.
</p>
</p>
</loop_area>
</loop_area>
</p>
</p>
<br />
==== Erzeuger-Verbraucher-Problem ====
<p>
<p>
{{#index:Producer-Consumer-Problem|Erzeuger-Verbraucher-Problem}}
Mit "entblockieren" ist hier das Ändern des [[Prozesszustände|Prozesszustands]] des ersten Prozesses aus der Warteschlange in den [[Prozesszustände|Zustand "Bereit"]] gemeint.
Ein ähnliches und oft verwendetes Beispiel ist das sogenannte '''Producer-Consumer-Problem''' (auf deutsch: '''Erzeuger-Verbraucher-Problem'''). Es ist beispielsweise beschrieben bei:
* <cite>Glatz+2010</cite>, Kapitel 4.3.3
* <cite>Tanenbaum+2009</cite>, Kapitel 2.3.5
* Wikipedia: http://de.wikipedia.org/wiki/Erzeuger-Verbraucher-Problem
* http://www.nt.fh-koeln.de/fachgebiete/inf/diplom/semwork/beispiele/erzver/erzver.html
</p>
</p>


<br />
<br />
==== Philosophenproblem ====
<p>
<p>
{{#index:Dining-Philosophers-Problem|Problem der speisenden Philosophen|Philosophenproblem}}
Nach diesen grundlegenden Definitionen folgen mit dem [[Mutex]] und dem [[Zählsemaphor]] zwei konkretere Konzepte, anhand derer die Einsatzmöglichkeiten von Semaphoren gezeigt werden.
Sehr bekannt ist auch das '''Dining-Philosophers-Problem''' (auf deutsch: '''Problem der speisenden Philosophen''' oder kurz: '''Philosophenproblem'''). Es wurde von [http://de.wikipedia.org/wiki/Edsger_W._Dijkstra Edsger Wybe Dijkstra] in seinem Aufsatz [http://www.cs.utexas.edu/users/EWD/ewd03xx/EWD310.PDF Hierarchical ordering of sequential processes] veröffentlicht. Es ist u.a. beschrieben bei:
* <cite>Tanenbaum+2009</cite>, Kapitel 2.5.1
* Wikipedia: http://de.wikipedia.org/wiki/Speisende_Philosophen
</p>
</p>


<br />
== So geht es weiter: ==
<p>
<p>
Bevor jedoch näher auf diese Probleme eingegangen werden kann, sind zunächst die atomaren Operationen <span style="font-family:Courier">P()</span> und <span style="font-family:Courier">V()</span> zu erläutern.
<loop_area type="arrangement"><loop_toc> </loop_toc></loop_area>
</p>
</p>


<br />
<br />
==== Atomare Operationen auf Semaphore ====
== Aufgabe 1 ==
<p>
<p>
Möchte ein Prozess in seinen kritischen Abschnitt eintreten, so muss er zunächst die Funktion '''<span style="font-family:Courier">P(s)</span>''' (bzw. '''<span style="font-family:Courier">down(s)</span>''') aufrufen. Hier wird geprüft, ob die Zählvariable des übergebenen Semaphors <span style="font-family:Courier">s</span> noch einen Wert größergleich Eins (>=1) besitzt.
<loop_area type="task">
</p>
<loop_task title="Warum up() und down()?" id="5fa9787b5e556">
<p>
<p>
* Falls ja: verringere den Wert der Zählvariablen um 1 und verlasse die Funktion wieder (der kritische Abschnitt darf also betreten werden).
Erläutere warum es Sinn macht, dass die <span style="font-family:Courier">P()</span>-Operation auch als <span style="font-family:Courier">down()</span>-Operation betitelt wird, und warum analog die <span style="font-family:Courier">V()</span>-Operation als <span style="font-family:Courier">up()</span> betitelt wird.
</p>
</p>
<p>
</loop_task>
* Falls nein: Der aufrufende Prozess wird angehalten ([[Prozesszustände|blockiert]]) und in die Warteschlange des Semaphors <span style="font-family:Courier">s</span> eingereiht (der kritische Abschnitt darf noch nicht betreten werden).
</loop_area>
</p>
<p>
Am Ende der Bearbeitung eines kritischen Abschnitts muss der betreffende Prozess die Funktion '''<span style="font-family:Courier">V(s)</span>''' (bzw. '''<span style="font-family:Courier">up(s)</span>''') aufrufen. Der Wert der Zählvariable des übergebenen Semaphors <span style="font-family:Courier">s</span> wird um Eins erhöht, und falls sich in der Warteschlange des Semaphors ein (oder mehrere) Prozess(e) befinden, so entferne den ersten daraus und ändere seinen Zustand in [[Prozesszustände|bereit]]. Bei der nächsten Zuteilung der CPU kann dieser damit seinen kritischen Abschnitt betreten.
</p>
</p>


<br />
<br />
==== Aufgabe 1 ====
== Aufgabe 2 ==
<p>
<p>
<loop_area type="task">
<loop_area type="task">
<loop_task title="Irgendwas">
<loop_task title="P() und V() sind atomar" id="5fa9787b5e55d">
<p>
<p>
Was ist beim [[Semaphore#Erzeuger-Verbraucher-Problem|Erzeuger-Verbraucher-Problem]] das "Irgendwas"?
Die <span style="font-family:Courier">[[Semaphore#Definition:_P.28.29-Operation_eines_Semaphors|P()]]</span>- und <span style="font-family:Courier">[[Semaphore#Definition:_V.28.29-Operation_eines_Semaphors|V()]]</span>-Operation ist jeweils als [[Das_Problem_des_ungünstigsten_Moments#Definition:_Atomare_Aktion|atomare Operation]] definiert.
</p>
<p>
Was bedeutet dies für die Ausführung dieser beiden Operationen?
</p>
</p>
</loop_task>
</loop_task>
Zeile 120: Zeile 126:


<br />
<br />
==== Aufgabe 2 ====
== Aufgabe 3 ==
<p>
<p>
<loop_area type="task">
<loop_area type="task">
<loop_task title="Operationen auf Semaphore">
<loop_task title="P() und V() und die Zustände" id="5fa9787b5e564">
<p>
<p>
Erkennst du, dass die Funktionsnamen <span style="font-family:Courier">down()</span> und <span style="font-family:Courier">up()</span> Sinn machen? Erläutere warum!
Wenn die <span style="font-family:Courier">[[Semaphore#Definition:_P.28.29-Operation_eines_Semaphors|P()]]</span>-Operation ausgeführt wird, dann ändert sich gegebenenfalls der Zustand desjenigen Prozesses, der die <span style="font-family:Courier">P()</span>-Operation aufgerufen hat.
</p>
</p>
<p>
<p>
Warum hat Dijkstra die Funktionen ursprünglich <span style="font-family:Courier">P()</span> und <span style="font-family:Courier">V()</span> genannt?
* Von welchem alten Zustand in welchen neuen Zustand erfolgt hier ggf. die Änderung?
</p>
<br />
<p>
Wie ist das bei der <span style="font-family:Courier">[[Semaphore#Definition:_V.28.29-Operation_eines_Semaphors|V()]]</span>-Operation? Ändert sich hier eventuell auch der Zustand des Prozesses, der die <span style="font-family:Courier">V()</span>-Operation aufgerufen hat?
</p>
<p>
* Falls ja: Von welchem alten Zustand in welchen neuen Zustand erfolgt hier ggf. die Änderung?
* Falls nein: Was ändert sich dann?
</p>
</p>
</loop_task>
</loop_task>
Zeile 135: Zeile 149:


<br />
<br />
== Aufgabe 4 ==
<p>
<p>
Dieses Kapitel wird in der weiterführenden Literatur behandelt:
<loop_area type="task">
<loop_task title="V()-Operation und die Warteschlange" id="5fa9787b5e56b">
<p>
In der [[Semaphore#Definition:_V.28.29-Operation_eines_Semaphors|Definition zur V()-Operation]] heisst es:
</p>
</p>
<p>
<p>
<loop_area type="notice">'''Weiterführende Literatur'''
* ''Wenn die Zählvariable den Wert Null hat, dann entblockiere den ersten Prozess der Warteschlange.''
<p>
<cite>Mandl+2013</cite> erläutert das Semaphor-Konzept in Kapitel 6.2.2. Die Lektüre dieser Quelle sei ausdrücklich empfohlen.
</p>
</p>
<p>
<p>
<small>Studierende sind oftmals berechtigt, eine PDF-Version dieses Buches ohne entstehende Kosten [[Hinweise für Studierende#Downloadbare Bücher von Springerlink|über ihre Hochschulen von Springerlink zu beziehen.]]</small>
Kann es passieren, dass der Wert der Zählvariablen gleich Null ist, aber kein Prozess entblockiert werden kann, weil die Warteschlange leer ist?
</p>
</p>
</loop_task>
</loop_area>
</loop_area>
</p>
</p>


<div class="autoit_do_not_print">
<br />
<br />
<hr />
<hr />
<sub>Diese Seite steht unter der [http://creativecommons.org/licenses/by/3.0/deed.de Creative Commons Namensnennung 3.0 Unported Lizenz] [http://creativecommons.org/licenses/by/3.0/deed.de http://i.creativecommons.org/l/by/3.0/80x15.png]
<sub>Diese Seite steht unter der [http://creativecommons.org/licenses/by/3.0/deed.de Creative Commons Namensnennung 3.0 Unported Lizenz] [http://creativecommons.org/licenses/by/3.0/deed.de http://i.creativecommons.org/l/by/3.0/80x15.png]
</sub>
</sub>
</div>

Aktuelle Version vom 13. Dezember 2021, 17:41 Uhr

Der niederländische Informatiker Edsger Wybe Dijkstra hat das Semaphor-Konzept in den 1960er-Jahren entwickelt, und in seinem Artikel Co-Operating Sequential Processes vorgestellt. Auf Wikipedia findet sich ein Hinweis zur Namensherkunft des Begriffs Semaphor.

Wie im weiteren Verlauf dieses Abschnitts noch zu sehen sein wird, können mit Hilfe des Semaphor-Konzepts eine Reihe von Problemen der Prozess-Synchronisation gelöst werden. Als großer Vorteil der Semaphore wird noch zu erkennen sein, dass sie dabei auf aktives Warten verzichten, und somit nicht den Nachteil der Verschwendung von CPU-Zeit haben.

Zunächst einige Definitionen:


Definition: Semaphor

Definition

Unter einem Semaphor versteht man eine Datenstruktur, welche einen ganzzahligen Zähler, sowie eine Warteschlange bereitstellt. Zusätzlich sind zwei atomare Operationen  P()  und  V()  auf diese Datenstruktur definiert.


Ein ganzzahliger Zähler ist in der Programmierung beispielsweise eine einfache Integer-Variable. Diese kann negative oder positive ganzzahlige Werte annehmen. Der ganzzahlige Zähler einer Semaphore hingegen kann keine negativen Werte annehmen.

Eine Warteschlange ist eine klassische Datenstruktur in der Informatik, die nach dem FIFO-Prinzip (First In, First Out) arbeitet. Sie dient hier zur geordneten Aufnahme von Prozessen.

Die Operation P() wird in einigen Quellen auch als down()-Operation betitelt, analog up() anstatt V().


Definition: Binärer Semaphor

Definition

Unter einem binären Semaphor versteht man einen Semaphor, dessen ganzzahliger Zähler nur die Werte 0 oder 1 annehmen kann.

Ein binärer Semaphor besitzt gemäß seiner Definition ebenso eine Warteschlange und auch die auf ihm operierenden P()- und V()-Operationen.


Definition: P()-Operation eines Semaphors

Definition

Die P()-Operation eines Semaphors ist als atomare Operation wie folgt definiert:

  • Hat die Zählervariable einen positiven Wert (>0), dann verringere den Wert der Zählvariablen um 1.
  • Wenn die Zählvariable den Wert 0 hat, dann blockiert die P()-Operation den aufrufenden Prozess und fügt ihn an das Ende ihrer Warteschlange hinzu.

Mit "blockieren" ist hier das Ändern des Prozesszustands des die P()-Operation aufrufenden Prozesses in den Zustand "Blockiert" gemeint.


Definition: V()-Operation eines Semaphors

Definition

Die V()-Operation eines Semaphors ist als atomare Operation wie folgt definiert:

  • Wenn die Warteschlange nicht leer ist, dann entblockiere den ersten Prozess der Warteschlange.
  • Ist die Warteschlange leer, dann erhöhe den Wert der Zählervariable um 1.

Mit "entblockieren" ist hier das Ändern des Prozesszustands des ersten Prozesses aus der Warteschlange in den Zustand "Bereit" gemeint.


Nach diesen grundlegenden Definitionen folgen mit dem Mutex und dem Zählsemaphor zwei konkretere Konzepte, anhand derer die Einsatzmöglichkeiten von Semaphoren gezeigt werden.

So geht es weiter:


Aufgabe 1

Aufgabe

Erläutere warum es Sinn macht, dass die P()-Operation auch als down()-Operation betitelt wird, und warum analog die V()-Operation als up() betitelt wird.


Aufgabe 2

Aufgabe

Die P()- und V()-Operation ist jeweils als atomare Operation definiert.

Was bedeutet dies für die Ausführung dieser beiden Operationen?


Aufgabe 3

Aufgabe

Wenn die P()-Operation ausgeführt wird, dann ändert sich gegebenenfalls der Zustand desjenigen Prozesses, der die P()-Operation aufgerufen hat.

  • Von welchem alten Zustand in welchen neuen Zustand erfolgt hier ggf. die Änderung?


Wie ist das bei der V()-Operation? Ändert sich hier eventuell auch der Zustand des Prozesses, der die V()-Operation aufgerufen hat?

  • Falls ja: Von welchem alten Zustand in welchen neuen Zustand erfolgt hier ggf. die Änderung?
  • Falls nein: Was ändert sich dann?


Aufgabe 4

Aufgabe

In der Definition zur V()-Operation heisst es:

  • Wenn die Zählvariable den Wert Null hat, dann entblockiere den ersten Prozess der Warteschlange.

Kann es passieren, dass der Wert der Zählvariablen gleich Null ist, aber kein Prozess entblockiert werden kann, weil die Warteschlange leer ist?