Laeufer



  • Hallo,

    wie der Name sagt habe ich vor ein Thread-Rennen zu schreiben. Das ist mit der Improved Console und Events Realisiert.

    Die Threads(4stk.) sollten von links nach rechts laufen,

    -also kursor nach rechts bewegen-> schreiben,
    -kursor eins nach rechts-> schreiben usw.

    Beim ersten Start machte das Programm "etwas", doch derzeit nichts. Ich weiss auch nicht mehr warum, da ich ehrlich gesagt den Überblick verloren habe.

    Ich hoffe Ihr könnt mir helfen.

    In den kommentaren habe ich die eigentliche Idee beschrieben, sollte ein wenig helfen.

    #include "ic.hpp"
    #include <iostream>
    #include <conio.h>
    #include <math.h>
    #include <time.h>
    
    using namespace std;
    using namespace ic;
    
    const int N=4;	// Thread größe
    HANDLE hThread[N];
    
    CRITICAL_SECTION cs_console; //Synchronisation der Zugriffe auf die console
    
    struct THREAD_DATA{	//Daten der Threads
    	int ID;
    	Color Farbe;	//Farbe des Cursors, ist nicht benutzt
    	char Symbol;	// Cursor Symbol, aktuell '*'
    	int Bahnnummer; 
    	HANDLE StartEv; // so wird NUR durch das setzen von "Start_Ev/Stop_Ev"
    	HANDLE StopEv;	// alle Events aller Threads gesetzt (alle Threads bekommen das Signal, zur selben zeit)
    };
    
    THREAD_DATA TData[N]; // Der oben definierte Struct
    DWORD WINAPI Laeufer(void *); // Threadfunktion
    
    void main(){
    
    	//-------------------------Initialisieren---------------//
    	con.setTitle("--------Laeufer----------");
    	cout << "Starten mit 's' " << endl << endl;
    
    	InitializeCriticalSection(&cs_console);
    
    	HANDLE StartEvent = CreateEvent(NULL,false,false,"StartEvent");
    	HANDLE StopEvent = CreateEvent(NULL,false,false,"StopEvent");
    
    	//-----------------N Threads erstellen--------------------------//
    	for(int i=0;i<N;i++){
    		TData[i].ID=i;
    		TData[i].Farbe=(Color)(FG_RED+i)%(FG_RED+4); // Zufällige Farbe
    		TData[i].Symbol='*';	// Konstant
    		TData[i].Bahnnummer=0;	// Konstant
    		TData[i].StartEv=StartEvent;
    		TData[i].StopEv=StopEvent;
    
    		hThread[i] = CreateThread(NULL,0,Laeufer,&TData[i],0,NULL);
    
    		if(hThread[i]==NULL)cout << "Thread wurde nicht erzeugt, Fehler " << GetLastError() << endl;
    	}
    
    	//--------------Kontrolle, Eingabeschleife--------------//
    	srand((unsigned)time(NULL));
    
    	bool Stop=false;
    	while(!Stop){
    
    		if(_kbhit()){
    			char c=_getche();
    			if(c=='s')SetEvent(StartEvent);break;
    			if(c=='q')SetEvent(StopEvent);Stop=true;break;  //Schleife beenden
    			}
    		if(WaitForSingleObject(StopEvent,INFINITE)==WAIT_OBJECT_0) Stop=true; // Auf das Stop Event des Threads(Läufer) warten
    		}
    
    	//-------------------Ressourcen schliessen--------------------//
    	DWORD nret = WaitForMultipleObjects(N,hThread,true,10000);
    	if(nret==WAIT_TIMEOUT){
    		for(int i=0;i<N;i++){
    		TerminateThread(hThread[i],-1);
    		}
    	}
    
    	CloseHandle(StartEvent);
    	CloseHandle(StopEvent);
    
    	DeleteCriticalSection(&cs_console);
    
    	while(_kbhit());
    
    }
    
    DWORD WINAPI Laeufer(void *Data){
    
    	THREAD_DATA *Daten=(THREAD_DATA*)Data; // Anpassen der Parameter
    	srand((unsigned)time(NULL));
    
    	EnterCriticalSection(&cs_console);
    	con.setCurPos(20,Daten->ID);
    	con.setTextColor(FG_BLUE);
    	LeaveCriticalSection(&cs_console);
    
    	cout << Daten->Symbol; //Startpunkt
    
    	// Aufs StartEvent warten
    	while(true){
    		if(WaitForSingleObject(Daten->StartEv,100)==WAIT_OBJECT_0)
    			break;
    		if(WaitForSingleObject(Daten->StopEv,100)==WAIT_OBJECT_0)
    			break;
    	}
    
    	int x=(rand()%1000)+100;  // Zufällige Wartezeit
    
    	//-----------Bis zur 70ten Spalte(Das Ziel) bewegen-------------//
    	EnterCriticalSection(&cs_console);
    	for(int i=0;i<70;i++){
    		con.setCurPos(Daten->ID+i,2);cout << Daten->Symbol;Sleep(x);
    		Daten->Bahnnummer=Daten->Bahnnummer+1; // für Rückgabe
    	}
    	LeaveCriticalSection(&cs_console);
    	// Ziel erreicht, an Threads Stop Event senden
    	SetEvent(Daten->StopEv);
    	EnterCriticalSection(&cs_console);
    	con.setCurPos(0,6); cout << "Sieger: " << Daten->ID;
    	LeaveCriticalSection(&cs_console);
    
    	return Daten->Bahnnummer; // Nicht benutzt
    }
    


  • Ohne deine Code mal en Detail durchgeschaut zu haben, habe ich folgede Frage: Warum willst du beim drücken einer Taste immer die Schleife beenden ?

    void main() // int main(int argc, char** argv) wird heute eher benutzt
    { 
      ...
      // Ich habe mal den Code ein wenig anders formatiert.
      bool Stop=false;
      while(!Stop)
      {
        if(_kbhit())
        {
          char c=_getche();
    
          if(c == 's')
            SetEvent(StartEvent);
          break; // Springt aus der Schleife !!!
          // Der folgende Code ist dadurch unnütz
          if(c == 'q')
            SetEvent(StopEvent);
          Stop=true;
          break;  //Schleife beenden
        }
        if(WaitForSingleObject(StopEvent,INFINITE) == WAIT_OBJECT_0) 
          Stop=true; // Auf das Stop Event des Threads(Läufer) warten
      }
      //-------------------Ressourcen schliessen--------------------//
    
      ...
    }
    


  • es war so gedacht das die Threads dadurch enden. Jedenfalls habe ich den code ein wenig geändert. Jetzt läuft einer der 4 Threads die anderen aber machen garnichts 😕 .

    Die Threads enden auch immmer durch das TerminateThread()

    Der Thread 'Win32-Thread' (0xdec) hat mit Code -1073741510 (0xc000013a) geendet.
    Der Thread 'Win32-Thread' (0xad4) hat mit Code -1073741510 (0xc000013a) geendet.
    Der Thread 'Win32-Thread' (0x950) hat mit Code -1073741510 (0xc000013a) geendet.
    Der Thread 'Win32-Thread' (0x9a0) hat mit Code -1073741510 (0xc000013a) geendet.
    Der Thread 'Win32-Thread' (0xd04) hat mit Code -1073741510 (0xc000013a) geendet.
    Das Programm "[2496] Ereignisse(Events).exe: Systemeigen" wurde mit Code -1073741510 (0xc000013a) beendet.
    
    #include "ic.hpp" //Die Improved Console
    #include <iostream>
    #include <conio.h>
    #include <math.h>
    #include <time.h>
    
    using namespace std;
    using namespace ic;
    
    const int N=4;	// Thread größe
    HANDLE hThread[N];
    
    CRITICAL_SECTION cs_console; //Synchronisation der Zugriffe auf die console
    
    struct THREAD_DATA{	//Daten der Threads
    	int ID;
    	Color Farbe;	//Farbe des Cursors, ist nicht benutzt
    	char Symbol;	// Cursor Symbol, aktuell '*'
    	int Bahnnummer; 
    	HANDLE StartEv; // so wird NUR durch das setzen von "Start_Ev/Stop_Ev"
    	HANDLE StopEv;	// alle Events aller Threads gesetzt (alle Threads bekommen das Signal, zur selben zeit)
    };
    
    THREAD_DATA TData[N]; // Der oben definierte Struct
    DWORD WINAPI Laeufer(void *); // Threadfunktion
    
    void main(){
    
    	//-------------------------Initialisieren---------------//
    	con.setTitle("--------Laeufer----------");
    	cout << "Starten mit 's' " << endl << endl;
    
    	InitializeCriticalSection(&cs_console);
    
    	HANDLE StartEvent = CreateEvent(NULL,false,false,"StartEvent");
    	HANDLE StopEvent = CreateEvent(NULL,true,false,"StopEvent");
    
    	//-----------------N Threads erstellen--------------------------//
    	for(int i=0;i<N;i++){
    		TData[i].ID=i;
    		TData[i].Farbe=(Color)(FG_RED+i)%(FG_RED+4); // Zufällige Farbe
    		TData[i].Symbol='*';	// Konstant
    		TData[i].Bahnnummer=0;	// Konstant
    		TData[i].StartEv=StartEvent;
    		TData[i].StopEv=StopEvent;
    
    		hThread[i] = CreateThread(NULL,0,Laeufer,&TData[i],0,NULL);
    
    		if(hThread[i]==NULL)cout << "Thread wurde nicht erzeugt, Fehler " << GetLastError() << endl;
    	}
    
    	//--------------Kontrolle, Eingabeschleife--------------//
    	srand((unsigned)time(NULL));
    
    	bool Stop=false;
    	while(Stop==false){
    		if(_kbhit()){
    			char c=_getche();
    			switch(c){
    				case's':PulseEvent(StartEvent);break;
    				case'q':SetEvent(StopEvent);Stop=true;break;  //Threads & While-Schleife beenden
    				default:break;
    			}
    			if(WaitForSingleObject(StopEvent,INFINITE)==WAIT_OBJECT_0) Stop=true;break; // Auf das Stop Event des Threads(Läufer) warten
    		}
    	}
    
    	//-------------------Ressourcen schliessen--------------------//
    	DWORD nret = WaitForMultipleObjects(N,hThread,true,10000);
    	if(nret==WAIT_TIMEOUT){
    		for(int i=0;i<N;i++){
    		TerminateThread(hThread[i],-1);
    		}
    	}
    
    	CloseHandle(StartEvent);
    	CloseHandle(StopEvent);
    
    	DeleteCriticalSection(&cs_console);
    
    	while(_kbhit());
    
    }
    
    DWORD WINAPI Laeufer(void *Data){
    
    	THREAD_DATA *Daten=(THREAD_DATA*)Data; // Anpassen der Parameter
    	srand((unsigned)time(NULL));
    
    	EnterCriticalSection(&cs_console);
    	con.setCurPos(0,Daten->ID);
    	con.setTextColor(FG_RED);
    	LeaveCriticalSection(&cs_console);
    
    	cout << Daten->Symbol << endl; //Startpunkt
    
    	// Aufs StartEvent warten
    	while(true){
    		if(WaitForSingleObject(Daten->StartEv,100)==WAIT_OBJECT_0)
    			break;
    	}
    
    	int x=(rand()%10)+100;  // Zufällige Wartezeit
    
    	//-----------Bis zur 70ten Spalte(Das Ziel) bewegen-------------//
    	EnterCriticalSection(&cs_console);
    	for(int i=0;i<70;i++){
    		if(WaitForSingleObject(Daten->StopEv,100)==WAIT_OBJECT_0)
    			break;
    		con.setCurPos(Daten->ID+i,1);cout << Daten->Symbol;Sleep(x);
    		Daten->Bahnnummer=Daten->Bahnnummer+1; // für Rückgabe
    	}
    	LeaveCriticalSection(&cs_console);
    	// Ziel erreicht, an Threads Stop Event senden
    	SetEvent(Daten->StopEv);
    	EnterCriticalSection(&cs_console);
    	con.setCurPos(0,6); cout << "Sieger: " << Daten->ID;
    	LeaveCriticalSection(&cs_console);
    
    	return Daten->Bahnnummer; // Nicht benutzt
    }
    


  • Uhh deine Thread-Synchronisation sieht nicht gut aus. 😞

    Ich kann das Verhalten deines Programms komplett nachvollziehen sofern nach dem Systemstart _kbhit() nur einmal eine Zahl != 0 zurückliefert.

    while(Stop==false){
            if(_kbhit()){
                char c=_getche();
                switch(c){
                    case's':PulseEvent(StartEvent);break;
                    case'q':SetEvent(StopEvent);Stop=true;break;  //Threads & While-Schleife beenden
                    default:break;
                }
                if(WaitForSingleObject(StopEvent,INFINITE)==WAIT_OBJECT_0) Stop=true;break; // Auf das Stop Event des Threads(Läufer) warten
            }
        }
    

    Dann würde deine Schleife nämlich an dem WaitForSingleObject() unendlich lange auf StopEvent warten, während die Threads laufen.

    DWORD WINAPI Laeufer(void *Data){
    ...
    // Aufs StartEvent warten
        while(true){
            if(WaitForSingleObject(Daten->StartEv,100)==WAIT_OBJECT_0)
                break;
        }
    

    Ok, die Threads dürften bis hier ohne Problem laufen. Aber danach passiert folgendes:

    //-----------Bis zur 70ten Spalte(Das Ziel) bewegen-------------//
        EnterCriticalSection(&cs_console);
        for(int i=0;i<70;i++){
            if(WaitForSingleObject(Daten->StopEv,100)==WAIT_OBJECT_0)
                break;
            con.setCurPos(Daten->ID+i,1);cout << Daten->Symbol;Sleep(x);
            Daten->Bahnnummer=Daten->Bahnnummer+1; // für Rückgabe
        }
        LeaveCriticalSection(&cs_console);
        // Ziel erreicht, an Threads Stop Event senden
        SetEvent(Daten->StopEv);
        EnterCriticalSection(&cs_console);
        con.setCurPos(0,6); cout << "Sieger: " << Daten->ID;
        LeaveCriticalSection(&cs_console);
    

    Thread X startet und nimmt die CS (Critical Section) in Anspruch. Wenn jetzt irgentein anderer Thread startet, wird er durch die CS blockiert. Ist ja der Sinn von CS. Sobald der Thread X aber die CS wieder freigibt, wird sofort das StopEvent in den Signaled Zustand überführt s.d. der Haupthread fortfahren kann (WaitForSingleObject(StopEvent...), die Schleife beendet und danach alle Threads terminiert. 😞


Anmelden zum Antworten