Problem mit critical Section
-
Hallo, ich habe 2 Threads. Ein Produzenten und einen Konsumenten.
Der Produzent soll die produzierten Objekte in eine Queue legen und der Konzument soll sich diese abholen.
Nun habe ich versucht eine Thread sichere queue zu schreiben:
#include <queue> using namespace std; #ifndef Queue_Thread_sicher__ #define Queue_Thread_sicher__ template<class T> class Queue_Thread_sicher { private: CRITICAL_SECTION CriSect; queue<T> *q; public: //Konstruktor Queue_Thread_sicher() { q= new queue<T>(); InitializeCriticalSection(&CriSect); } //Destruktor ~Queue_Thread_sicher() { DeleteCriticalSection(&CriSect); delete q; } //liefern den Wert des letzten Elements . T back () { EnterCriticalSection(&CriSect); return q->back(); LeaveCriticalSection(&CriSect) ; } //gibt zurück, ob die queue leer ist bool empty() { EnterCriticalSection(&CriSect); return q->empty(); LeaveCriticalSection(&CriSect); } //liefern den Wert des ersten Elements . T front () { EnterCriticalSection(&CriSect); return q->front(); LeaveCriticalSection(&CriSect) ; } //löscht das letzte element void pop () { EnterCriticalSection(&CriSect); q->pop(); LeaveCriticalSection(&CriSect) ; } //Fügt ein Element hinzu void push (T t) { EnterCriticalSection(&CriSect); q->push(t); LeaveCriticalSection(&CriSect) ; } //gibt die Größe an float zize () { EnterCriticalSection(&CriSect); return q->size(); LeaveCriticalSection(&CriSect) ; } }; #endifDas Problem ist aber, dass der Produzent ein Objekt produzieren und in die Queue legen kann. Der Konsument nimmt sich diese raus und "verbraucht" es.
Dann kann der Produzent aber keine weiteren Objekte in die Queue legen, denn er bekommt (anscheinend) keinen Zugriff auf die critical Section.Immer wenn ich dann das Programm unterbreche hängt er in der schleife, bei der er (Der produzent) auf den Zugang zur critical Section wartet.
Was ist Falsch?
-
Hier noch der Code zum Testen:
#include <iostream> #include <winsock2.h> #include "Queue_Thread_sicher.h" using namespace std; DWORD WINAPI Produzent(LPVOID data) { //data in Queue_Thread_sicher umwandeln Queue_Thread_sicher<int*> *q = (Queue_Thread_sicher<int*>*) data; while (true) { //produziere für immer int *x = new int (700); //erzeuge integer zahl q->push(x); //Füge diese in die Queue_Thread ein cout << *x<<" produziert"<< endl; } return (DWORD)data; } DWORD WINAPI Konsument(LPVOID data) { //data in Queue_Thread_sicher umwandeln Queue_Thread_sicher<int*> *q = (Queue_Thread_sicher<int*>*) data; while (true) { //konsumiere für immer while (!q->empty()) //wenn die queue nicht leer ist { int *x=q->back(); //hole Element aus der Queue cout << *x<<" konsumiert"<< endl; delete x; //lösche das Objekt q->pop(); //Reduziere die Queue um 1 } } return (DWORD)data; } int main () { //die Threadsichere Queue erzeugen Queue_Thread_sicher<int*> *q = new Queue_Thread_sicher<int*>(); HANDLE hThread[2]; //Handle für die Threads DWORD dwThreadID[2]; //DWORD für die Threads //Beide Threads starten hThread[0] = CreateThread(NULL, 0, Produzent, (LPVOID)q, 0, &dwThreadID[0]); hThread[1] = CreateThread(NULL, 0, Konsument, (LPVOID)q, 0, &dwThreadID[1]); //Auf die Threads warten WaitForMultipleObjects( 2, hThread, TRUE, INFINITE); return 1; }Als Ausgabe erscheint nur:
700produziert 700konsumiert
und dann nichts mehr.
Wie musß ich die Klasse "Queue_Thread_sicher" ändern, damit es funktioniert?
(Oder ist woanders ein Fehler?)
-
MisterX schrieb:
float zize () { EnterCriticalSection(&CriSect); return q->size(); LeaveCriticalSection(&CriSect) ; }Ist dir klar, was hier nicht passiert?
-
MFK schrieb:
MisterX schrieb:
float zize () { EnterCriticalSection(&CriSect); return q->size(); LeaveCriticalSection(&CriSect) ; }Ist dir klar, was hier nicht passiert?
Leider nein!
Bitte schreib was nicht passiert!
-
LeaveCriticalSection passiert nicht. Nach der return-Anweisung ist die Methode beendet.
Edit: Gerade erst gesehen: Warum in aller Welt float?
-
LoooooL <Brett vorm Kopf zur seite schieb> <schäm>
Ich frage mich dann nur, warum ich ein Element produzieren und eins kosumieren konnte, wenn ich nie die critical Section freigebe.
Es hätte nach dem Produzieren doch der Konsument keinen Eintritt mehr bekommen dürfen.
-
Warum float?
Habe ich mich auch gewundert, aber bei den ganzzahligen typen int, long,
unsigned int, unsigned long, schreibt er immer als Warnung, dass Datenverlußte
auftreten könnten, bei float schreibt der Compiler die warnung nicht.
-
MisterX schrieb:
Es hätte nach dem Produzieren doch der Konsument keinen Eintritt mehr bekommen dürfen.
Nö. In push hast du das Problem ja nicht.
Dein Code ist übrigens ein gutes Beispiel für nicht exception-sicheren Code. Warum die Klasse einen Zeiger für die Queue verwendet, habe ich auch nicht verstanden.
-
So, DANKE nochmals
(Manchmal sieht man die Bäume vor lauter Wald nicht)Hier die jetzt funktionierende Version (leider noch ohne Exception Handling)
#include <queue> using namespace std; #ifndef Queue_Thread_sicher__ #define Queue_Thread_sicher__ template<class T> class Queue_Thread_sicher { private: CRITICAL_SECTION CriSect; queue<T> q; public: //Konstruktor Queue_Thread_sicher() { InitializeCriticalSection(&CriSect); } //Destruktor ~Queue_Thread_sicher() { DeleteCriticalSection(&CriSect); } //liefern den Wert des letzten Elements . T back () { EnterCriticalSection(&CriSect); T help=q.back(); LeaveCriticalSection(&CriSect) ; return help; } //gibt zurück, ob die queue leer ist bool empty() { EnterCriticalSection(&CriSect); bool help= q.empty(); LeaveCriticalSection(&CriSect); return help; } //liefern den Wert des ersten Elements . T front () { EnterCriticalSection(&CriSect); T help=q.front(); LeaveCriticalSection(&CriSect) ; return help; } //löscht das letzte element void pop () { EnterCriticalSection(&CriSect); q.pop(); LeaveCriticalSection(&CriSect) ; } //Fügt ein Element hinzu void push (T t) { EnterCriticalSection(&CriSect); q.push(t); LeaveCriticalSection(&CriSect) ; } //gibt die Größe an float zize () { EnterCriticalSection(&CriSect); float f= q.size(); LeaveCriticalSection(&CriSect) ; return f; } }; #endif
-
Oh man bin ich dumm.
Ich werde mich nochmal mit den Grundlagen beschäftigen bevor ich mit Winapi weitermache.
-
Obwohl du unter falschem Namen postest, ist die Idee gar nicht mal so schlecht
