Kritischer Abschnitt

Im Quelltext aller Prozesse oder Threads lassen sich Abschnitte identifizieren, welche entweder kritisch, oder unkritisch im Hinblick auf Race Conditions sind.


Definition: Kritischer Abschnitt

Definition

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.


Definition: Unkritischer Abschnitt

Definition

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.


Hinweis

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!


Beispiel zu kritischen Abschnitten

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.

  1. public class Beispiel_Kritischer_Abschnitt {
  2.  
  3. static int counter = 0;
  4.  
  5. public static class Thread_A extends Thread {
  6. 	public void run() {
  7. 		do_something();          // unkritisch
  8. 		count_from_10();         // kritisch !!!
  9. 		do_something_else();     // unkritisch
  10. 	}
  11. 	private void do_something() {
  12. 		// unkritischer Abschnitt
  13. 		System.out.println("Thread_A: unkritisch");	
  14. 	}
  15. 	private void count_from_10() {
  16. 		// Vorsicht: kritischer Abschnitt!
  17. 		counter = 10;
  18. 		counter++;
  19. 		counter++;
  20. 		System.out.println("A-Counter: " + counter);		
  21. 	}
  22. 	private void do_something_else() {
  23. 		// unkritischer Abschnitt
  24. 		System.out.println("Thread_A: wieder unkritisch");	
  25. 	}
  26. }
  27.  
  28. public static class Thread_B extends Thread {
  29. 	public void run() {
  30. 		System.out.println("Thread_B ist gestartet.");
  31. 		counter = 20;
  32. 		counter++;
  33. 		counter++;
  34. 		counter++;
  35. 		counter++;
  36. 		counter++;
  37. 		counter++;
  38. 		System.out.println("B-Counter: " + counter);
  39. 	}
  40. }
  41.  
  42. public static void main(String[] args) {
  43. 	Thread a = new Thread_A();
  44. 	Thread b = new Thread_B();
  45. 	a.start();
  46. 	b.start();
  47. }
  48.  
  49. }


Aufgabe 1

Aufgabe
Abschnitte in Thread_B

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:

  • Werden von Thread_A dann nur Befehle aus unkritischen Abschnitten ausgeführt, so gibt es keine Probleme.

  • Falls aber von Thread_A Befehle aus dem kritischen Abschnitt ausgeführt werden, so kommt es zu Race Conditions.


Wichtig

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.


Hinweis

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.


Aufgabe 2

Aufgabe
Viele andere Betriebsmittel

  • Nenne möglichst viele Betriebsmittel!
  • Und was war nochmal die zentrale Aufgabe des Betriebssystems?


Durch die Beantwortung der letzten Frage sollte klar werden:


Wichtig

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.


Aufgabe 3

Aufgabe
Warum Systemaufrufe?

Warum wird hier an Systemaufrufe erinnert? Erläutere den Zusammenhang von Systemaufrufen (wenn Betriebsmittel angesprochen werden) und der Synchronisation von Prozessen bzw. Threads!


Aufgabe 4

Aufgabe
Zwei Prozesse und kritische Abschnitte

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.

  • Darf A seinen kritischen Abschnitt ausführen, obwohl der zuvor unterbrochene Prozess B sich noch innerhalb seines kritischen Bereichs befindet? (Dann wären beide Prozesse gleichzeitig in ihren kritischen Abschnitten.)

  • Oder muss A zunächst warten, bis B seinen kritischen Abschnitt verlassen hat?

Begründe deine Entscheidung! (Sind alle Mitglieder deiner Lerngruppe auch dieser Meinung?)



Diese Seite steht unter der Creative Commons Namensnennung 3.0 Unported Lizenz 80x15.png