3.2.11.1.3 Kritischer Abschnitt

[gesichtete Version][gesichtete Version]
Keine Bearbeitungszusammenfassung
Keine Bearbeitungszusammenfassung
Zeile 125: Zeile 125:
</p>
</p>


<br />
<p>
<p>
<loop_area type="notice">
<loop_area type="notice">

Version vom 2. November 2013, 23:45 Uhr

{{#index:kritischer Abschnitt|Abschnitt, kritisch|unkritischer Abschnitt|Abschnitt, unkritisch}} 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 gemeinsam genutzte Betriebsmittel besitzen.


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

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();
 8 		count_from_10();
 9 		do_something_else();
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

Wo finden sich 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.

Die Synchronisations-Aufgabe besteht nur 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-Variablen.

Du musst verstehen, dass dies nur ein sehr einfaches Beispiel ist, und dass speziell bei Threads und "selbstgeschaffenen" Betriebsmitteln (wie der Integer-Variablen) der Programmierer selbst in der Pflicht zur Synchronisation ist. (Java bietet dafür das Schlüsselwort synchronized.)

Es gibt jedoch noch viele andere Betriebsmittel; an die Zentrale Aufgabe eines Betriebssystems sei erinnert: die Betriebsmittelverwaltung.

Somit ist das Betriebssystem für die Synchronisation von Prozessen und Threads zuständig, welche auf gemeinsam genutzte (und vom Betriebssystem verwaltete) Betriebsmittel zugreifen wollen. Erinnert sei in diesem Zusammenhang an Systemaufrufe.


Aufgabe 2

Aufgabe

Warum wird hier an Systemaufrufe erinnert? Erläutere den Zusammenhang mit Betriebsmitteln und der Synchronisation von Prozessen und Threads!



Diese Seite steht unter der Creative Commons Namensnennung 3.0 Unported Lizenz http://i.creativecommons.org/l/by/3.0/80x15.png