Twitter und Facebook-Anbindung
X
Tweet Follow @twitterapi
!!! Anbindung an twitter und facebook öffnen !!!

Wenn Ihnen mein Online-Buch gefällt,
dann bedanken Sie sich doch mit einer kleinen Spende...

30.1 CriticalSections mit Hilfe der Win API

30.1 CriticalSections mit Hilfe der Win API

Im folgenden Beispiel werde ich zeigen, wie man mit Hilfe der Win API einen kritischen Abschnitt realisieren kann. Dabei werde ich auf das Beispiel von vorhin aufsetzen, in welchem zwei Threads mehrere Sachen auf der Konsole ausgaben.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
					
#include <windows.h>
#include <stdio.h>
#include "ThreadWrapper.h"

struct SMyThreadData {
	int			iStart;
	int			iEnd;
	int			iID;
	LPCRITICAL_SECTION	pCriticalSection;
};



// Funktion, welche durch den Thread ausgeführt wird //////////////////////////
DWORD ThreadFunc(CThreadWrapper<SMyThreadData>* pThread) {
	__try {
		EnterCriticalSection(pThread->GetData().pCriticalSection);

		for (int iCount = pThread->GetData().iStart; iCount < pThread->GetData().iEnd && !pThread->IsTerminated(); iCount++) {
			printf("Thread: %i - %i\n", pThread->GetData().iID, iCount);
			Sleep(100);
		} // end of for
	} __finally {
		LeaveCriticalSection(pThread->GetData().pCriticalSection);
	} // end of __try

	return 0;
} // ThreadFunc ///////////////////////////////////////////////////////////////



// Hauptfunktion der Anwendung ////////////////////////////////////////////////
int main(int argc, char** argv) {
	CRITICAL_SECTION		sCriticalSection;
	InitializeCriticalSection(&sCriticalSection);

	SMyThreadData			sData1		= {0, 10, 1, &sCriticalSection};
	SMyThreadData			sData2		= {1000, 1010, 2, &sCriticalSection};

	CThreadWrapper<SMyThreadData>*	pThread1	= new CThreadWrapper<SMyThreadData>(&ThreadFunc, sData1);
	CThreadWrapper<SMyThreadData>*	pThread2	= new CThreadWrapper<SMyThreadData>(&ThreadFunc, sData2);

	printf("START\n");

	pThread1->Resume();
	pThread2->Resume();

	// Warten, bis alle Threads fertig sind
	while (!pThread1->IsFinished() || !pThread2->IsFinished()) Sleep(1);

	delete pThread1;
	delete pThread2;

	DeleteCriticalSection(&sCriticalSection);
	
	printf("ENDE\n");

	return 0;
} // main /////////////////////////////////////////////////////////////////////
					

Ausgabe:

START
Thread: 1 - 0
Thread: 1 - 1
Thread: 1 - 2
Thread: 1 - 3
Thread: 1 - 4
Thread: 1 - 5
Thread: 1 - 6
Thread: 1 - 7
Thread: 1 - 8
Thread: 1 - 9
Thread: 2 - 1000
Thread: 2 - 1001
Thread: 2 - 1002
Thread: 2 - 1003
Thread: 2 - 1004
Thread: 2 - 1005
Thread: 2 - 1006
Thread: 2 - 1007
Thread: 2 - 1008
Thread: 2 - 1009
ENDE
		

In den Zeilen 5 bis 10 sieht man wieder die Definition der Datenstruktur, welche dem Threadobjekt übergeben wird. Hier ist jetzt noch ein Zeiger für den kritischen Abschnitt hinzu gekommen, da ich für beide Threads den gleichen verwenden will.

Wie man dann in den Zeilen 15 bis 28 sehen kann, benutze ich für die Threads meine Templateklasse und die zweite Art der Threadfunktion, welche mein Template erlaubt. Als aller erstes betrete ich einen "try-finaly" Block. Dies ist eine reine Vorsichtsmaßnahme, denn falls nach dem Betreten des Abschnittes ein Laufzeitfehler auftritt, habe ich sonst keine Möglichkeit mehr, diesen kritischen Abschnitt wieder zu verlassen. Anschließend, in Zeile 17, betrete ich nun diesen kritischen Abschnitt und kann dann meine eigentliche Arbeit verrichten. Wie man an der Schleifenbedingung sehen kann, baue ich wieder ein Mechanismus ein, welcher es mir erlaubt, die Arbeit des Threads vorzeitig zu beenden. In Zeile 24 verlasse ich wieder den Abschnitt und komme zum Ende der Threadfunktion.

Ab der Zeile 33 finden Sie jetzt die "main" Funktion. Dort ist jetzt lediglich das Erzeugen des kritischen Abschnittes, sowie seine Freigabe, hinzugekommen. Außerdem übergebe ich die Referent des Abschnittswächters an die verwendeten Strukturen. Das Anlegen eines kritischen Abschnittes, findet in Zeile 34 und 35 statt. Das Freigeben findet man in Zeile 54.

Wie Sie jetzt an der Ausgabe sehen können, haben beide Threads wieder die gemeinsame Konsole verwendet, aber darauf gewartet, bis der andere mit seiner Ausgabe fertig ist. Ich hatte zusätzlich in der Threadfunktion das "Sleep" hoch gesetzt, um dieses Verhalten mehr zu unterstreichen. Zwar ist dies in der Ausgabe nicht ersichtlich, aber wenn Sie sich diesen Quelltext kopieren und ausführen, werden Sie sehen, dass der erste Thread jetzt eine Weile braucht, um zum Ende zu kommen und das der zweite der Weile wartet, bevor er loslegt.

Nun kann man statt der Funktion "EnterCriticalSection" auch die Funktion "TryEnterCriticalSection" benutzen, welche sofort "false" zurück gibt, falls schon jemand in diesem Abschnitt ist. Der Thread der nicht rein kommt, kann jetzt entweder in einer Schleife darauf warten, dass er irgendwann doch noch rein kommt oder etwas ganz anderes tun und somit diesen Bereich überspringen. Dadurch verhindert man, dass ein Thread Ewigkeiten auf etwas wartet, was im schlimmsten Fall nie eintritt.

Zum Seitenanfang
Zum Inhaltsverzeichnis

© Copyright by Thomas Weiß, 2009 - 2012