3.2.11.3.1.1 Wechselseitiger Ausschluss

[gesichtete Version][gesichtete Version]
Zeile 207: Zeile 207:
</p>
</p>
<p>
<p>
Hier ist ein Bild mit beiden Quelltexten nebeneinander.[[:File:aktives_warten_vs_mutex.jpg]]
Hier ist ein Bild mit beiden Quelltexten nebeneinander.[[:Datei:aktives_warten_vs_mutex.jpg]]
</p>
</p>
<br />
<br />

Version vom 6. Februar 2015, 17:46 Uhr

Wechselseitiger Ausschluss

Der folgende Quellcode ist bereits aus dem Kapitel Kritischer Abschnitt bekannt:

 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 }


Erläuterungen zu Listing 1

Zwei Threads A und B greifen jeweils auf die counter-Variable zu. Die counter-Variable stellt damit ein gemeinsam genutztes Betriebsmittel dar.

In beiden Threads lassen sich kritische Abschnitte identifizieren. Es muss dafür gesorgt werden, dass sich immer nur ein Thread zur Zeit in seinem kritischen Abschnitt befindet.

Dies nennt man den wechselseitigen Ausschluss: Wenn sich ein Thread in seinem kritischen Abschnitt befindet, dann muss ausgeschlossen sein, dass auch der andere Thread in seinen kritischen Abschnitt eintritt.


Hinweis

Du kennst bereits das aktive Warten (mit TSL), durch das ein wechselseitiger Ausschluss realisiert werden kann. Jedoch verschwendet das aktive Warten CPU-Zeit.

Ein Mutex kommt nun anstatt des aktiven Wartens zum Einsatz. Somit verschwindet auch der Nachteil der CPU-Zeitverschwendung.


Mutex in Listing 1 einbauen

Um einen Mutex in Listing 1 einzubauen, muss diese Datenstruktur zunächst erzeugt werden, um anschließend die P()- und V()-Operationen an den geeigneten Stellen aufzurufen.

Listing 2 zeigt dieses Vorgehen, direkt darunter gibt es einige Erläuterungen.


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


Erläuterungen zu Listing 2 mit Mutex

Entscheident sind hier die Zeilen 3, 20, 27, 40, 51 und 58.

In Zeile 3 wird zunächst eine Variable mit dem Namen mutex vom Datentyp Semaphor deklariert.

In Zeile 58 wird der Mutex durch den Aufruf von CreateSemaphor(1) initialisiert. Die Methode CreateSemaphor() ist dabei als Systemaufruf zu verstehen, d.h. das Betriebssystem erzeugt hier die Semaphor-Datenstruktur. Der Übergabeparameter 1 sorgt dafür, dass der ganzzahlige Zähler des Semaphors mit dem Wert 1 initialisiert wird.

Der kritische Abschnitt von Thread_A liegt in den Zeilen 22 bis 25.
Direkt davor (in Zeile 20) wird die Methode P(mutex); aufgerufen, direkt danach (in Zeile 27) wird die Methode V(mutex); aufgerufen.

Der kritische Abschnitt von Thread_B liegt in den Zeilen 42 bis 49.
Direkt davor (in Zeile 40) wird die Methode P(mutex); aufgerufen, direkt danach (in Zeile 51) wird die Methode V(mutex); aufgerufen.


Hinweis

Der hier abgedruckte Quellcode zu Listing 2 ist in dieser Form nicht ausführbar. Er soll lediglich beispielhaft verdeutlichen, an welchen Stellen zusätzliche Operationen im Bezug auf den Mutex zur Realisierung des wechselseitigen Ausschlusses eingefügt werden müssen.


Aufgabe 1

Aufgabe

Vergleiche den obigen Quellcode aus Listing 2 (Mutex) einmal mit dem bereits bekannten Quellcode mit dem Beispiel des Aktiven Wartens (mit while).

Hier ist ein Bild mit beiden Quelltexten nebeneinander.Datei:aktives_warten_vs_mutex.jpg


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