Threadprobleme



  • Hallo,
    ich habe einen Button der, wenn man auf ihn klickt, einen Thread startet. In diesem Thread sollen so lange Daten generiert werden bis wieder auf den Button geklickt wird und der Thread beendet wird. Jetzt habe ich also sozusagen eine Endlosschleife in meinem Thread. Wenn ich kompiliere bekomme ich immer einen Fehler " 0xC0000005: Access Violation ". Was mache ich nur falsch? Wenn ich den Thread starte klappt alles, erst wenn ich ihn wieder beenden will kommt der Fehler. Ich beenden den Thread mit "TerminateThread", ich weis dass man das nicht tun sollte, aber ich habe ja keine andere Wahl. Kann mir irgendwer helfen?

    OnButton()
    {
        InitializeCriticalSection(&Section);
    
        if(clicked==true)
        {
            DWORD lpExitCode;
            GetExitCodeThread(hThread,&lpExitCode);
            TerminateThread(hThread,lpExitCode);
    
            clicked = false;
        }
        else
        {
            clicked = true;
    
            hThread = CreateThread(NULL,0,ThreadFunc,NULL,0,NULL);
            WaitForSingleObject(hThread,100);
        }
    
        DeleteCriticalSection(&Section);
    }
    
    DWORD WINAPI ThreadFunc(LPVOID data)
    {
    	EnterCriticalSection(&Section);
    
    	int *x = 0;
    	int *y = 0;
    	int count = 0;
    	x = new int [];
    	y = new int [];
    	srand(1);
    
    	while (clicked == true)
    	{
    		Sleep(50);
    		count = count + 1;
    		x[count] = count;
    		y[count] = rand() % 2;
    	}
    
    	LeaveCriticalSection(&Section);
    
    	return((DWORD)data);
    }
    

    Ich bin mit meinem Latein wirklich am Ende. Hab schon alles ausprobiert. Komisch ist dass ich nicht immer ein Access Violation bekomme. Manchmal klappt alles reibungslos, aber das kommt eher selten vor. In den meisten Fällen bekomme ich den Fehler. Bitte helft mir.



  • Sieht so aus als löschst du dem Thread das critical section Objekt.

    Edit: nicht vergessen x und y mit delete[] freizugeben (das verursacht aber nicht dein Problem, sondern es werden Speicherlecks erzeugt).


  • Mod

    Aber mal eine ganz andere Frage: Welchen Sinn macht es einen Lock für die gesamte Rechenzeit eines Threads aufrechtzu erhalten. Dann kann man sich den Thread doch auch komplett sparen...



  • ihoernchen schrieb:

    Sieht so aus als löschst du dem Thread das critical section Objekt.

    Wirklich? Wie und wo denn? Bzw. wie muss ich es denn dann richtig machen? Ich hab schon damit rumprobiert, aber bei allen anderen Konstellationen ist mir das Programm immer sofort abgestürzt.

    ihoernchen schrieb:

    Edit: nicht vergessen x und y mit delete[] freizugeben (das verursacht aber nicht dein Problem, sondern es werden Speicherlecks erzeugt).

    Hatte ich wirklich vergessen, Danke. War aber wie du schon vermutest hast nicht das Problem.

    Martin Richter schrieb:

    Aber mal eine ganz andere Frage: Welchen Sinn macht es einen Lock für die gesamte Rechenzeit eines Threads aufrechtzu erhalten. Dann kann man sich den Thread doch auch komplett sparen...

    Wenn ich mir den Thread spare, würde aber der Rest meines Programms blockiert. Das ist ja dann auch nicht Sinn der Sache. Ich könnte ja dann noch nicht mal mehr auf den Button klicken um den Vorgang zu beenden. Ich hatte leider keine bessere Idee wie ich es machen könnte. Wenn es ohne Thread geht, sag mir gerne wie, ich versuch es eh immer so gut wie zu umgehen. Wie würdest du es denn machen?


  • Mod

    Und für wasbarauchst Du eine Critical Section?
    Jeder andere Threae der diese Critical Section anfasst, wird auch blockieren...
    und das genau für die Dauer des Threads. Dein Main-Thread blockiert also wieder 😉



  • Martin Richter schrieb:

    Und für wasbarauchst Du eine Critical Section?
    Jeder andere Threae der diese Critical Section anfasst, wird auch blockieren...
    und das genau für die Dauer des Threads. Dein Main-Thread blockiert also wieder 😉

    Mit den Critical Sections an sich kenn ich mich nicht so gut aus. Allerdings hab ich gelesen dass man Threads eigentlich immer absichern sollte. Bisher hab ich das dann eben immer mit den Critical Sections gemacht, da mir Mutexe oder sonstiges noch komplizierter erscheinen und ich dachte die Sections reichen bei meinen Programmen schon aus.
    Ich hab sie jetzt mal auskommentiert. Eigentlich ändert sich überhaupt nichts. Der selbe Fehler kommt, wie immer. Mit den Sections dürfte es also nicht zusammen hängen.



  • x = new int [];
    y = new int [];
    

    Wie groß sind deine Arrays?



  • Du brauchst so einen "Schutz" (critical section) nur, wenn Threads sich "absprechen" müssen. Z.B. wenn Daten in einem Thread verändert und in einem 2. ausgewertet / angezeigt / was auch immer werden. Lokale Daten, die nur in dem Thread bekannt sind (wie in deinem Thread) müssen nicht abgesichert werden.
    Die Variable clicked brauch keine Absicherung.

    Das ganze, wenn es nicht nur zum Spielen ist, sieht sehr komisch aus. Wenn ich mich nicht täusche wartet WaitForSingleObject(thread....) solange bis thread beendet wurde. Womit dein Programm einen Deadlock haben sollte sobald der Thread gestartet wurde.



  • Ich würde mal behaupten das mit dem WaitForSingleObject sollte nicht das Problem denn da ist ein Timeout definiert. Weit aus Kritischer seh ich das beenden, Die Variable clicked wird nei auf false gesetzt also läuft der Thread weiter, dann kommt die Abfrage auf den Exitcode, die total belanglos weil nicht ausgewertet, und zum schluß damit das alles noch Rund wird schießt du einfach den Thread ab, wobei ich vermute das da irgendwas schief geht dalso der noch läuft wärend Speicherbereiche schon nicht mehr existent sind oder so.

    if(clicked==true)
        {
            clicked = false;
            DWORD lpExitCode;
            //hier jetzt ne schleife oder so und warten das sich der Thread selbst beendet sollte er das in einer gewissen Zeit nicht dann erst TerminateThread
                GetExitCodeThread(hThread,&lpExitCode);
    
            TerminateThread(hThread,lpExitCode);
        }
        else
        {
            clicked = true;
    
            hThread = CreateThread(NULL,0,ThreadFunc,NULL,0,NULL);
            WaitForSingleObject(hThread,100);
        }
    


  • ihoernchen schrieb:

    x = new int [];
    y = new int [];
    

    Wie groß sind deine Arrays?

    Naja, das kommt ja darauf an wie lange ich Daten generieren lasse. Wenn ich den Button einmal anklicke fängt die Datengenerierung an und wenn ich ein zweites mal klicke soll es wieder aufhören. Ich habe eine Verzögerung eingebaut, Sleep(50);, damit nicht zu viele Daten generiert werden. Wie groß die Verzögerung am Ende sein wird, weis ich aber noch nicht. Das heißt die Arrays müssen ganz schön was einstecken.

    ihoernchen schrieb:

    Du brauchst so einen "Schutz" (critical section) nur, wenn Threads sich "absprechen" müssen. Z.B. wenn Daten in einem Thread verändert und in einem 2. ausgewertet / angezeigt / was auch immer werden. Lokale Daten, die nur in dem Thread bekannt sind (wie in deinem Thread) müssen nicht abgesichert werden.
    Die Variable clicked brauch keine Absicherung.

    Hm, ja das ist mir eigentlich auch bekannt, aber ich wollte eben irgendwann auf den count Wert zugreifen und ihn in einem Edit-Feld anzeigen lassen. Das habe ich leider noch nicht geschafft, da es aus einem Thread raus anscheinend nicht so einfach geht Daten abzugreifen. Und irgendwann muss ich auch die x- und y-Werte abgreifen, dafür generiere ich sie ja eigentlich. Die sollen dann irgendwann auch mal übergeben werden. Bräuchte ich dann dafür eine Absicherung?



  • Du solltest auch nicht auf Daten eines Threads zugreifen sondern der Thread soll die Daten bereitstellen.
    Von Thread aus eine Nachricht an das Fenster zur Anzeige im EDIT und gut ist es.



  • CTecS schrieb:

    Weit aus Kritischer seh ich das beenden, Die Variable clicked wird nei auf false gesetzt also läuft der Thread weiter, dann kommt die Abfrage auf den Exitcode, die total belanglos weil nicht ausgewertet, und zum schluß damit das alles noch Rund wird schießt du einfach den Thread ab, wobei ich vermute das da irgendwas schief geht dalso der noch läuft wärend Speicherbereiche schon nicht mehr existent sind oder so.

    Also das mit der clicked Variable sehe ich auch so, die hatte ich auch Anfangs zuerst auf false gesetzt. Ich dachte ja auch eigentlich dass es ausreichen würde die auf false zu setzten damit der Thread sich beendet, aber leider tut er das nicht. Den Exitcode brauche ich doch für die TerminateThread(), ohne den geht es doch nicht, oder? Also zumindest sagt mir der Kompiler dass die Funktion nicht nur einen Parameter akzeptiert. Naja und dann zu guter letzt muss ich den Thread doch abschießen, er beendet sich halt einfach nicht. Ich hab auch schon ganz viel darüber gelesen dass man das nicht machen soll, aber die Funktion muss ja für irgendwas gut sein.

    CTecS schrieb:

    if(clicked==true)
        {
            clicked = false;
            DWORD lpExitCode;
            //hier jetzt ne schleife oder so und warten das sich der Thread selbst beendet sollte er das in einer gewissen Zeit nicht dann erst TerminateThread
                GetExitCodeThread(hThread,&lpExitCode);
    
            TerminateThread(hThread,lpExitCode);
        }
        else
        {
            clicked = true;
    
            hThread = CreateThread(NULL,0,ThreadFunc,NULL,0,NULL);
            WaitForSingleObject(hThread,100);
        }
    

    Ich verstehe warum ich das machen soll, aber was soll denn in der Schleife passieren? Wenn ich da die Abfrage GetExitCodeThread() reinpacke, geht es nicht weil er dann motzt dass der Speicher überläuft. Wenn ich ein Sleep() reinpacke gehts auch nicht. Und nur ne Schleife ohne Anweisung bringt ja auch nix, die läuft ja einfach super schnell durch.



  • Unix-Tom schrieb:

    Du solltest auch nicht auf Daten eines Threads zugreifen sondern der Thread soll die Daten bereitstellen.
    Von Thread aus eine Nachricht an das Fenster zur Anzeige im EDIT und gut ist es.

    Geht das dann trotzdem mit SetDlgItemText(); ? Weil so habe ich das bisher nicht hinbekommen.


  • Mod

    Schon, wenn im Mainthread eine Nachrichtenschleife läuft und Du keine MFC Objekte benutzt, sondern Window Handles.



  • Hallo Leute,

    ich muss euch nochmal um Hilfe bitten. Ich bekomme diese Access Violation einfach nicht weg. Sitz jetzt schon seit 4 Tagen da dran und kann mir einfach nicht erklären wie das kommt. Der Debugger zeigt in der "dgbheap.c" immer auf folgende Zeile:

    if (_BLOCK_TYPE(pHead->nBlockUse) >= 0 && _BLOCK_TYPE(pHead->nBlockUse) < _MAX_BLOCKS)
    {
                    state->lCounts[_BLOCK_TYPE(pHead->nBlockUse)]++;
                    state->lSizes[_BLOCK_TYPE(pHead->nBlockUse)] += pHead->nDataSize;
                }
    

    Ich denke auch wie CTecS dass der Fehler wohl darin liegt dass sich der Thread nicht immer beendet. Das komische ist halt dass der Fehler nicht immer, aber meisstens auftritt. Manchmal bekomme ich einen Access Violation im Aufruflistenfenster, kann dann aber das Problem trotzdem ohne Probleme beenden. Manchmal hängt er sich aber auch auf wenn ich das Programm dann beenden will.
    Ich kann leider auch nicht "Debug >> Threads" aufrufen, erst wenn ich das Programm beendet hab, aber dann sehe ich ja nicht mehr den Thread der während des Programms gestartet wurde und wieder beendet werden sollte.

    Ich weis wirklich nicht mehr weiter, bitte helft mir.



  • Poste doch mal den Code so wie er läuft. Der Schnipsel da oben: da fehlt die Array Größe und der Thread schreibt ins Array ohne sich darum zu kümmern wie groß es ist. Count läuft von 0 bis unendlich.
    Ist das vielleicht das Problem?



  • Du wirst einen Überlauf im Heap haben. Dieser ist begrenzt und Du begrenzt Deine Schleife nicht. Integer sind schnell überlaufen.
    Für Deinen Thread noch einen Hinweis, vielleicht ein anderer Ansatz über eine Struktur zum Datenaustausch. Dann brauchst Du ihn auch nicht terminieren, sondern er kann sich selber beenden (macht er immer bei return). Als Beispiel:

    typedef struct{
    	CWnd *cWnd;
    	BOOL lpKillThread;
    	char Transfer[255];
    	int TransferNr;
    } THREAD_INFO;
    

    zB. *cWnd für Dein Editfeld.

    UINT tThread(LPVOID lpParam)
    {
    	// Get a THREAD_INFO pointer from the
    	// parameter that was passed in.
    	THREAD_INFO *lpThreadInfo = (THREAD_INFO *) lpParam;
    

    Klappt bisher immer. Ansonsten kannst Du bei einem einzigen Thread Events nutzen und mit WaitForSingleObject(event,0) abfragen.



  • Wie schon mehrfach Festgestellt wurde ist deine Array-Definition eher unsinnig und das wird auch dein Problem sein, wenn du die Werte dir eh nicht Merken willst dann Sende diese doch per PostMessage an deinen Mainwindow. An sonsten würde ich das Speichern der Daten einer Array-Klasse wie CUIntArray überlassen, denn da besteht nicht die gefahr über den Stack hinaus zu arbeiten, bzw. du brauchst dich nicht um Speicherreservierung und Freigabe zu kümmern.


Anmelden zum Antworten