CriticalSection in Threads
-
hustbaer schrieb:
Ändere '<= 5' in '< 5' damit der Code richtig ist, dann geht er auch.
Da bin ich ja voll auf den Leim getrampelt...

hustbaer schrieb:
So wie du es machst überschreibst du evtl. (je nach Compiler) einen Teil der CRITICAL_SECTION beim Zugriff auf das nicht vorhandene Element mit Index 5 (=das 6. Element).
EDIT: und ja, du solltest _beginthreadex verwenden statt CreateThread. Und die Stacksize mit 0 ist schon OK, 0 an der Stelle heisst einfach "Defaultwert bitte".
Dabei hatte ich solch einen "schönen" RT-Fehler beim "Clonen" des Stacks vermutet.
Wie war das "KISS" oder so ähnlich...

-
Ich hab's auch erst beim Durchsteppen gesehen

@Laines: der Output ist doch eh korrekt. Dadurch dass du keine Pause zwischen "unlock" und "lock" hast wird es ziemlich unvorhersehbar wann der Besitzer der CRITICAL_SECTION wechselt.
Wenn du das synchronisieren willst so dass erst Thread1 einmal drankommt zum Zählen, dann Thread2 einmal zum ausgeben, dann wieder 1 etc. - dann musst du EVENTs oder schlimmeres verwenden
-
Hier erstmal der Code wie weit er jetzt ist:
#include <iostream> #include <windows.h> #include <conio.h> #include <process.h> #include <stdio.h> using namespace std; // Gemeinsamme struktur struct gemeinsamme_daten{ int array[5]; }; // Object von Gemeinsamer Struktur gemeinsamme_daten daten; // Erstellen der Critical section CRITICAL_SECTION cs; // Event erzeugen HANDLE hEvent = CreateEvent( NULL, // default security attributes TRUE, // manual-reset event FALSE, // initial state is non signaled "Event" // object name ); // Funktion zum ersten Thread DWORD WINAPI ThreadProc1(LPVOID lpParam){ gemeinsamme_daten *p = (gemeinsamme_daten*) lpParam; int i(0); while(true){ EnterCriticalSection(&cs); for(int y(0); y < 5; y++){ p->array[y] = i; } i++; LeaveCriticalSection(&cs); } return 0; } // Funktion zum zweiten Thread DWORD WINAPI ThreadProc2(LPVOID lpParam){ gemeinsamme_daten *p = (gemeinsamme_daten*) lpParam; int i(0); while(true){ EnterCriticalSection(&cs); for(int y(0); y < 5; y++){ cout << p->array[y] << endl; } i++; LeaveCriticalSection(&cs); } return 0; } // +--------------------------------------------------------------------------- // + main - Methode // +--------------------------------------------------------------------------- int main(void) { // HANDLES und VARIABLEN HANDLE hThread1, hThread2; DWORD dwThreadId1, dwThreadId2; DWORD wait1, wait2; InitializeCriticalSection(&cs); hThread1 = CreateThread( NULL, // default security attributes 0, // use default stack size ThreadProc1, // thread function (LPVOID) &daten, // argument to thread function 0, // use default creation flags &dwThreadId1); // returns the thread identifier hThread2 = CreateThread( NULL, // default security attributes 0, // use default stack size ThreadProc2, // thread function (LPVOID) &daten, // argument to thread function 0, // use default creation flags &dwThreadId2); // returns the thread identifier while(true){ if (_kbhit()){ SetEvent( hEvent ); break; } Sleep(100); } wait1 = WaitForSingleObject( hThread1, INFINITE ); wait2 = WaitForSingleObject( hThread2, INFINITE ); // ENDE DeleteCriticalSection(&cs); system("Pause"); return 0; }Könnte mir jemand zeigen wie ich folgendes realisieren kann:
Ich möchte, das nach einem Tastendruck (_kbhit()) von der main aus beide Threads geordnet beendet werden. Das ganze soll mittels Events geschehen.
-
if(WaitForSingleObject(hEvent,0)==WAIT_TIMEOUT) break;^^ das da mußt du an geeigneter Stelle in die Hauptschleife bieder Threads einbauen, um auf deine SetEvent() reagieren zu können. (der beste Platz ist zwischen dem LeaveCriticalSection() und dem Schleifenabschluß)
-
Wenn ich es so mache gibt er mir 00000 aus und bleibt dann stehen obwohl ich keine taste gedrückt habe...
if(WaitForSingleObject(hEvent,0)==WAIT_TIMEOUT) break;Das abbuch Kriterium soll aber auch nicht ein time out sondern des hEvent sein was gesignald wird.
-
Nachtrag:
if(WaitForSingleObject(hEvent,INFINITE)==WAIT_OBJECT_0) break;Damit erziele ich komischerweise das gleiche Ergebnis.
-
// im Hauptprogramm, vor anlegen der Threads: hEvent = ::CreateEvent(0, true, 0, 0); if (!hEvent) { std::cout << "Dah, nix mit Event!" << std::endl; return 1; } // in der Schleife: if (::WaitForSingleObject(hEvent, 0) == WAIT_OBJECT_0) break; // im Hauptprogramm nach dem Warten auf nen Tastendruck: ::SetEvent(hEvent);
-
Danke jetzt geht es!
Jetzt hab ich aber noch eine Frage.
WaitForSingleObject(hEvent, 0)Was bewirt hier die 0. Und warum geht INFINITE (keine zeit Beschränkung) nicht?
-
Die 0 ist die max. Wartezeit, und INFINITE führt dazu dass "ewig" gewartet wird, d.h. die Funktion kehrt erst zurück wenn das Objekt "signaled" ist.
Da du an der Stelle nur abfragen willst ob es signaled ist und nicht warten übergibst du eben 0.
-
@Laines:
Kannst du noch einmal den gesamten Code posten, mit dem Beenden duch Tastendruck?