[gesichtete Version] | [gesichtete Version] |
Keine Bearbeitungszusammenfassung |
Kwastg (Diskussion | Beiträge) Keine Bearbeitungszusammenfassung |
||
(25 dazwischenliegende Versionen von 3 Benutzern werden nicht angezeigt) | |||
Zeile 1: | Zeile 1: | ||
< | |||
<loop_index id="5fa97866ea6b2">kritischer Abschnitt</loop_index><loop_index id="5fa978679d16e">Abschnitt, kritisch</loop_index><loop_index id="5fa978679d17f">unkritischer Abschnitt</loop_index><loop_index id="5fa978679d18e">Abschnitt, unkritisch</loop_index> | |||
Im Quelltext aller Prozesse oder Threads lassen sich Abschnitte identifizieren, welche entweder ''kritisch'', oder ''unkritisch'' im Hinblick auf [[Race Conditions]] sind. | Im Quelltext aller Prozesse oder Threads lassen sich Abschnitte identifizieren, welche entweder ''kritisch'', oder ''unkritisch'' im Hinblick auf [[Race Conditions]] sind. | ||
</p> | </p> | ||
<br /> | <br /> | ||
== Definition: Kritischer Abschnitt == | |||
<p> | <p> | ||
<loop_area type="definition"> | <loop_area type="definition"> | ||
<p> | <p> | ||
Unter einem '''kritischen Abschnitt''' versteht man Programmteile, die während ihrer Ausführung auf der CPU nicht durch kritische Abschnitte anderer Prozesse oder Threads unterbrochen werden dürfen, sofern die beteiligten Prozesse oder Threads gemeinsam genutzte Betriebsmittel | Unter einem '''kritischen Abschnitt''' versteht man Programmteile, die während ihrer Ausführung auf der CPU nicht durch kritische Abschnitte anderer Prozesse oder Threads unterbrochen werden dürfen, sofern die beteiligten Prozesse oder Threads auf gemeinsam genutzte Betriebsmittel zugreifen. | ||
</p> | </p> | ||
</loop_area> | </loop_area> | ||
</p> | |||
<p> | |||
Es sei hier klar hingewiesen auf die Tatsache, dass kritische Abschnitte während ihrer Ausführung sehr wohl unterbrochen werden dürfen, und das passiert in der Realität auch häufig, zum Beispiel durch [[Interrupt-Controller|Interrupts]]. | |||
</p> | |||
<p> | |||
Es kommt aber immer darauf an, was genau während der Unterbrechung getan wird. Sobald gemeinsam genutzte Betriebsmittel ins Spiel kommen, wird es im wahrsten Sinne des Wortes "kritisch" und ein Unterbrechungsverbot im Sinne der [[Kritischer_Abschnitt#Definition:_Kritischer_Abschnitt|obigen Definition]] droht. | |||
</p> | </p> | ||
<br /> | <br /> | ||
== Definition: Unkritischer Abschnitt == | |||
<p> | <p> | ||
<loop_area type="definition"> | <loop_area type="definition"> | ||
Zeile 44: | Zeile 52: | ||
<br /> | <br /> | ||
== Beispiel zu kritischen Abschnitten == | |||
<p> | <p> | ||
Das folgende Beispiel zeigt ein Java-Programm mit zwei Threads, bei deren Ausführung es zu Race Conditions kommt. Bei Thread_A werden durch spezielle Methoden kritische und unkritische Abschnitte gekennzeichnet. | Das folgende Beispiel zeigt ein Java-Programm mit zwei Threads, bei deren Ausführung es zu Race Conditions kommt. Bei Thread_A werden durch spezielle Methoden kritische und unkritische Abschnitte gekennzeichnet. | ||
</p> | </p> | ||
<p> | <p id="Listing_1"> | ||
<loop_listing title=" | <loop_listing title="Listing 1: Beispiele für kritische und unkritische Abschnitte" description="Ein Java-Programm mit zwei Threads. Bei Thread_A wechseln sich ein unkritischer, ein kritischer und noch ein unkritischer Abschnitt ab." id="5fa97866ea6c8"> | ||
<source lang="java" line="true"> | <source lang="java" line="true"> | ||
public class Beispiel_Kritischer_Abschnitt { | public class Beispiel_Kritischer_Abschnitt { | ||
Zeile 58: | Zeile 66: | ||
public static class Thread_A extends Thread { | public static class Thread_A extends Thread { | ||
public void run() { | public void run() { | ||
do_something(); | do_something(); // unkritisch | ||
count_from_10(); | count_from_10(); // kritisch !!! | ||
do_something_else(); | do_something_else(); // unkritisch | ||
} | } | ||
private void do_something() { | private void do_something() { | ||
Zeile 106: | Zeile 114: | ||
<br /> | <br /> | ||
== Aufgabe 1 == | |||
<p> | <p> | ||
<loop_area type="task"> | <loop_area type="task"> | ||
<loop_task title="Thread_B"> | <loop_task title="Abschnitte in Thread_B" id="5fa97866ea6d3"> | ||
<p> | <p> | ||
Wo finden sich bei Thread_B kritische bzw. unkritische Abschnitte? | Wo finden sich in [[Kritischer_Abschnitt#Listing_1|Listing 1]] bei Thread_B ''kritische'' bzw. ''unkritische'' Abschnitte? | ||
</p> | </p> | ||
</loop_task> | </loop_task> | ||
Zeile 119: | Zeile 128: | ||
<br /> | <br /> | ||
<p> | <p> | ||
Werden Thread_A und Thread_B nebenläufig ausgeführt, so kann praktisch jederzeit ein [[Vom_Batch-Job_zum_Multitasking#Definition:_Kontextwechsel|Kontextwechsel]] erfolgen. | Werden Thread_A und Thread_B [[Nebenläufigkeit|nebenläufig]] ausgeführt, so kann praktisch jederzeit ein [[Vom_Batch-Job_zum_Multitasking#Definition:_Kontextwechsel|Kontextwechsel]] erfolgen. | ||
</p> | </p> | ||
<p> | <p> | ||
Angenommen Thread_B befindet sich innerhalb seines kritischen Abschnitts, und es erfolgt der Kontextwechsel zu Thread_A: | Angenommen Thread_B befindet sich innerhalb seines kritischen Abschnitts, und es erfolgt der Kontextwechsel zu Thread_A: | ||
</p> | |||
<p> | |||
* Werden von Thread_A dann nur Befehle aus unkritischen Abschnitten ausgeführt, so gibt es keine Probleme. | * Werden von Thread_A dann nur Befehle aus unkritischen Abschnitten ausgeführt, so gibt es keine Probleme. | ||
</p> | |||
<p> | |||
* Falls aber von Thread_A Befehle aus dem kritischen Abschnitt ausgeführt werden, so kommt es zu [[Race Conditions]]. | * Falls aber von Thread_A Befehle aus dem kritischen Abschnitt ausgeführt werden, so kommt es zu [[Race Conditions]]. | ||
</p> | </p> | ||
Zeile 145: | Zeile 158: | ||
<loop_area type="notice"> | <loop_area type="notice"> | ||
<p> | <p> | ||
Bei dem hier gezeigten Java-Beispielcode konkurrieren jeweils zwei Threads um das gemeinsame Betriebsmittel einer einfachen Integer- | Bei dem hier gezeigten Java-Beispielcode konkurrieren jeweils zwei Threads um das gemeinsame Betriebsmittel einer einfachen Integer-Variable. | ||
</p> | </p> | ||
<p> | <p> | ||
Du musst verstehen, dass dies nur ein sehr einfaches Beispiel ist, und dass speziell bei Threads und "selbstgeschaffenen" Betriebsmitteln (wie der Integer- | Du musst verstehen, dass dies nur ein sehr einfaches Beispiel ist, und dass speziell bei Threads und "selbstgeschaffenen" Betriebsmitteln (wie der Integer-Variable) der Programmierer selbst in der Pflicht zur Synchronisation ist. <small>(Java bietet dafür das Schlüsselwort [http://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html synchronized].)</small> | ||
</p> | </p> | ||
</loop_area> | </loop_area> | ||
Zeile 155: | Zeile 168: | ||
<br /> | <br /> | ||
<p> | <p> | ||
Es gibt - neben der durch Programmierer selbst geschaffenen Variablen - noch viele andere Betriebsmittel. | Es gibt - neben der durch Programmierer "selbst geschaffenen" Variablen - noch viele andere Betriebsmittel. | ||
</p> | </p> | ||
<br /> | <br /> | ||
== Aufgabe 2 == | |||
<p> | <p> | ||
<loop_area type="task"> | <loop_area type="task"> | ||
<loop_task title="Viele andere Betriebsmittel"> | <loop_task title="Viele andere Betriebsmittel" id="5fa97866ea6dd"> | ||
<p> | <p> | ||
* Nenne möglichst viele Betriebsmittel! | * Nenne möglichst viele Betriebsmittel! | ||
Zeile 173: | Zeile 187: | ||
<br /> | <br /> | ||
<p> | <p> | ||
Durch die Beantwortung der letzten Frage | Durch die Beantwortung der letzten Frage sollte klar werden: | ||
</p> | </p> | ||
Zeile 186: | Zeile 200: | ||
<p> | <p> | ||
Erinnert sei in diesem Zusammenhang an Systemaufrufe. | Erinnert sei in diesem Zusammenhang an [[Kernel-Mode,_User-Mode_und_Systemaufrufe#Definition:_Systemaufruf|Systemaufrufe]]. | ||
</p> | </p> | ||
<br /> | <br /> | ||
== Aufgabe 3 == | |||
<p> | <p> | ||
<loop_area type="task"> | <loop_area type="task"> | ||
<loop_task title="Warum Systemaufrufe?"> | <loop_task title="Warum Systemaufrufe?" id="5fa97866ea6e7"> | ||
<p> | <p> | ||
Warum wird hier an Systemaufrufe erinnert? Erläutere den Zusammenhang | Warum wird hier an Systemaufrufe erinnert? Erläutere den Zusammenhang von Systemaufrufen (wenn Betriebsmittel angesprochen werden) und der Synchronisation von Prozessen bzw. Threads! | ||
</p> | </p> | ||
</loop_task> | </loop_task> | ||
Zeile 202: | Zeile 217: | ||
<br /> | <br /> | ||
== Aufgabe 4 == | |||
<p> | <p> | ||
<loop_area type="task"> | <loop_area type="task"> | ||
<loop_task title="Zwei Prozesse und kritische Abschnitte"> | <loop_task title="Zwei Prozesse und kritische Abschnitte" id="5fa97866ea6f1"> | ||
<p> | <p> | ||
Im Rahmen dieser Aufgabe existieren zwei Prozesse A und B, welche sich auf der CPU abwechseln. | Im Rahmen dieser Aufgabe existieren zwei Prozesse A und B, welche sich auf der CPU abwechseln. | ||
</p> | </p> | ||
<p> | <p> | ||
Prozess A benötigt als Betriebsmittel das DVD-Laufwerk | Prozess A benötigt als Betriebsmittel das DVD-Laufwerk. Es lassen sich also (ein oder mehrere) kritische Abschnitte in Prozess A identifizieren, in denen der Zugriff auf das genannte Betriebsmittel erfolgt. | ||
</p> | </p> | ||
<p> | <p> | ||
Prozess B benötigt als Betriebsmittel | Prozess B benötigt als Betriebsmittel die Datei foo.txt auf der Festplatte, in die hineingeschrieben wird. Auch dafür lassen sich (ein oder mehrere) kritische Abschnitte identifizieren. | ||
</p> | </p> | ||
<p> | <p> | ||
Zeile 228: | Zeile 244: | ||
</p> | </p> | ||
<p> | <p> | ||
Begründe deine Entscheidung! | Begründe deine Entscheidung! <small>(Sind alle Mitglieder deiner Lerngruppe auch dieser Meinung?)</small> | ||
</p> | </p> | ||
</loop_task> | </loop_task> |
Im Quelltext aller Prozesse oder Threads lassen sich Abschnitte identifizieren, welche entweder kritisch, oder unkritisch im Hinblick auf Race Conditions sind.
Unter einem kritischen Abschnitt versteht man Programmteile, die während ihrer Ausführung auf der CPU nicht durch kritische Abschnitte anderer Prozesse oder Threads unterbrochen werden dürfen, sofern die beteiligten Prozesse oder Threads auf gemeinsam genutzte Betriebsmittel zugreifen.
Es sei hier klar hingewiesen auf die Tatsache, dass kritische Abschnitte während ihrer Ausführung sehr wohl unterbrochen werden dürfen, und das passiert in der Realität auch häufig, zum Beispiel durch Interrupts.
Es kommt aber immer darauf an, was genau während der Unterbrechung getan wird. Sobald gemeinsam genutzte Betriebsmittel ins Spiel kommen, wird es im wahrsten Sinne des Wortes "kritisch" und ein Unterbrechungsverbot im Sinne der obigen Definition droht.
Unter einem unkritischen Abschnitt versteht man jeden Programmteil, der keinen kritischen Abschnitt darstellt.
Als Programmteil im Sinne der vorangegangenen Definitionen kann jeder Codeabschnitt mit der geforderten Eigenschaft gelten. Diese Programmteile lassen sich sowohl in einer Hochsprache wie Java, C, C++, Pascal, usw. identifizieren, als auch in Maschinencode oder Assembler.
Du musst dich daran erinnern, dass ein in einer Hochsprache wie Java, C, C++, Pascal, usw. angegebener Befehl in seiner Übersetzung in Maschinencode bzw. Assembler in mehrere kleine Befehle resultieren kann. Falls dir das entfallen war, so schau noch mal auf die Seite Vom_Quellcode_zum_Prozessor.
Ein Kontextwechsel findet immer zwischen zwei Maschinenbefehlen auf der CPU statt!
Das folgende Beispiel zeigt ein Java-Programm mit zwei Threads, bei deren Ausführung es zu Race Conditions kommt. Bei Thread_A werden durch spezielle Methoden kritische und unkritische Abschnitte gekennzeichnet.
public class Beispiel_Kritischer_Abschnitt {
static int counter = 0;
public static class Thread_A extends Thread {
public void run() {
do_something(); // unkritisch
count_from_10(); // kritisch !!!
do_something_else(); // unkritisch
}
private void do_something() {
// unkritischer Abschnitt
System.out.println("Thread_A: unkritisch");
}
private void count_from_10() {
// Vorsicht: kritischer Abschnitt!
counter = 10;
counter++;
counter++;
System.out.println("A-Counter: " + counter);
}
private void do_something_else() {
// unkritischer Abschnitt
System.out.println("Thread_A: wieder unkritisch");
}
}
public static class Thread_B extends Thread {
public void run() {
System.out.println("Thread_B ist gestartet.");
counter = 20;
counter++;
counter++;
counter++;
counter++;
counter++;
counter++;
System.out.println("B-Counter: " + counter);
}
}
public static void main(String[] args) {
Thread a = new Thread_A();
Thread b = new Thread_B();
a.start();
b.start();
}
}
Wo finden sich in Listing 1 bei Thread_B kritische bzw. unkritische Abschnitte?
Werden Thread_A und Thread_B nebenläufig ausgeführt, so kann praktisch jederzeit ein Kontextwechsel erfolgen.
Angenommen Thread_B befindet sich innerhalb seines kritischen Abschnitts, und es erfolgt der Kontextwechsel zu Thread_A:
Die Synchronisations-Aufgabe besteht nun darin sicherzustellen, dass sich immer nur ein Prozess oder Thread zur Zeit in seinem kritischen Abschnitt befindet.
Dazu werden auf den folgenden Seiten mehrere Konzepte vorgestellt.
Bei dem hier gezeigten Java-Beispielcode konkurrieren jeweils zwei Threads um das gemeinsame Betriebsmittel einer einfachen Integer-Variable.
Du musst verstehen, dass dies nur ein sehr einfaches Beispiel ist, und dass speziell bei Threads und "selbstgeschaffenen" Betriebsmitteln (wie der Integer-Variable) der Programmierer selbst in der Pflicht zur Synchronisation ist. (Java bietet dafür das Schlüsselwort synchronized.)
Es gibt - neben der durch Programmierer "selbst geschaffenen" Variablen - noch viele andere Betriebsmittel.
Durch die Beantwortung der letzten Frage sollte klar werden:
Das Betriebssystem ist für die Synchronisation von Prozessen und Threads zuständig, welche auf gemeinsam genutzte Betriebsmittel zugreifen wollen.
Erinnert sei in diesem Zusammenhang an Systemaufrufe.
Warum wird hier an Systemaufrufe erinnert? Erläutere den Zusammenhang von Systemaufrufen (wenn Betriebsmittel angesprochen werden) und der Synchronisation von Prozessen bzw. Threads!
Im Rahmen dieser Aufgabe existieren zwei Prozesse A und B, welche sich auf der CPU abwechseln.
Prozess A benötigt als Betriebsmittel das DVD-Laufwerk. Es lassen sich also (ein oder mehrere) kritische Abschnitte in Prozess A identifizieren, in denen der Zugriff auf das genannte Betriebsmittel erfolgt.
Prozess B benötigt als Betriebsmittel die Datei foo.txt auf der Festplatte, in die hineingeschrieben wird. Auch dafür lassen sich (ein oder mehrere) kritische Abschnitte identifizieren.
Weitere Betriebsmittel werden von den Prozessen nicht benötigt.
Angenommen Prozess B wird auf der CPU ausgeführt und befindet sich mitten in der Abarbeitung eines kritischen Abschnitts. Es erfolgt der Kontextwechsel zu Prozess A. Dieser arbeitet zunächst einen unkritischen Abschnitt ab, möchte dann aber einen kritischen Abschnitt betreten.
Begründe deine Entscheidung! (Sind alle Mitglieder deiner Lerngruppe auch dieser Meinung?)
Diese Seite steht unter der Creative Commons Namensnennung 3.0 Unported Lizenz http://i.creativecommons.org/l/by/3.0/80x15.png