Thread von aussen beenden funktioniert nicht
-
Grüsse zusammen,
Wie man einen Thread von aussen beendet, meine ich zu wissen. Allerdings bin ich mir da jetzt nicht mehr so sicher. Hab inzwischen zwei Varianten ausprobiert und beide funktionieren aus meiner Meinung nach ganz seltsamen Gründen nicht.
1. Variante die ich ausprobiert habe:
MeineViewKlasse::IrgendeineFunktion(...) { // ... m_pEvent = new CEvent(FALSE, TRUE); AfxBeginThread(SearchThread, (LPVOID)m_pEvent); // ... } MeineViewKlasse::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { if(nChar == VK_ESCAPE) { m_pEvent->SetEvent(); } CListView::OnKeyDown(nChar, nRepCnt, nFlags); } static UINT SearchThread(LPVOID lpParam) { CEvent* pEvent = (CEvent*)lpParam; // ... while(/*irgend eine Bedingung*/) { if(::WaitForSingleObject(pEvent/*oder pEvent->m_hObject*/, 0) == WAIT_OBJECT_0) { break; } } }
2. Variante
Anstatt des CEvents habe ich mir eine globale Variable angelegt und wenn der Thread gestoppt werden sollte auf true gesetzt. Somit anstatt das WaitForSingleObject die globale Variable hingeschrieben.Aber in beiden Varianten ändert sich der Wert nie, wenn man Escape drückt und ich habe auch geschaut, SetEvent wird aufgerufen, aber nützt irgendwie nix. Mein Event wird nie signalisiert (oder wie man das auf Deutsch sagt) und meine Variable wurde nie von false auf true gesetzt. Also anderst gesagt, das break wurde absolut nie aufgerufen.
Wie kann sowas sein?
Grüssli
-
Hi,
wenn du Events benutzt, musst du da nicht auch irgendwo ein SetEvent() aufrufen, sonst weis ja dein Thread nie wann der Event eingetreten ist?EDIT: sorry, hab dein SetEvent() oben nicht gesehen!
lg
pixel
-
Sollte nicht statt dem break da ein return stehen?
-
Das break ist absolut korrekt. Es muss ein break dort stehen, damit am Ende alle Ressourcen aufgeräumt werden. Früher als noch kein Thread war, wurde anstatt das WaitForSingleObject im Thread ein GetAsyncKeyState(VK_ESCAPE) aufgerufen und das klappte wunderbar und ist schön aus der Funktion ausgestiegen. Mit dem Thread möchte ich jetzt verhindern, dass nicht die Meldung im Fenster kommt: "Programm reagiert nicht!", wenn ein Suchlauf läuft. Was auch alles wunderschön jetzt funktioniert, nur kann ich den Thread nicht abbrechen wenn ich will.
Aja und wie gesagt, das break wird gar nie aufgerufen. Da der Wert vom Event oder der Globalenvariable irgendwie nie geändert werden kann. Es wird zwar SetEvent aufgerufen, bzw. true der Globalenvariable zugewiesen, aber die Variable reagiert darauf nicht und bleibt beim alten Wert.
if(nChar == VK_ESCAPE) // Punkt 1 { G_bStopThread = true; } // Punkt 2 // Punkt 3
Diesen Code bin ich Schritt für Schritt im Debugger durchgegangen. An Punkt1 ist G_bStopThread == false. An Punkt2, welcher auch ausgeführt wird ist G_bStopThread == false. An Punkt3 ist G_bStopThread == false, wo es jetzt doch eigentlich true sein sollte. Ich habe auch meinen Thread überprüft. Der hat nirgends die Möglichkeit G_bStopThread einen Wert zuzuweisen. Er fragt ihn nur andauernd in der Schleife über eine If-Anweisung ab:
if(G_bStopThread) { // Wird nie ausgeführt! }
Also könnte echt hilfe benötigen. Hat denn niemand ne Ahnung woran es liegen könnte? Z.b. weil der Thread zu oft auf die Variable zugreift um sie zu lesen? Oder irgendsowas in der Richtung und wie könnte man es lösen? *am Verzweifeln ist*
Bzw. es gäbe vielleicht noch eine Idee. Ich kann doch auch Nachrichten an den Thread schicken mit PostThreadMessage oder? Wie kann ich auf so eine Nachricht im Arbeitsthread reagieren?
Grüssli
-
mach die variable mal 'volatile'. vielleicht hilfts...
-
Ja, bspw. so:
MSG msg; while(true) { PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ); // Is There A Message Waiting? if ( msg.message == WM_QUIT ) // Have We Received A Quit Message? { return FALSE; } else // If Not, Deal With Window Messages { TranslateMessage(&msg); // Translate The Message DispatchMessage(&msg); // Dispatch The Message } }
-
Kannst du ein minimalen, kompilierbaren Quellcode erstellen der den Fehler zeigt?
-
@net
probiert -> gehofft -> noch mehr gehofft -> Thread starten lassen -> Gehofft bis zum explodieren -> Escape gedrückt -> hoch enttäuscht ^^Hat keine Änderungen gebracht. Aber danke für den Versuch ^^
@connan
Und wenn keine Nachricht wartet? Also wie kann ich meinen Threadcode mit dem abrufen der Nachrichten kombinieren?Grüssli
-
dann hast du bestimmt zwei variablen mit dem namen 'G_bStopThread'. vielleicht eine als class member und eine globale, so dass die sich irgendwie überdecken...
lass die beim debuggen mal die adresse von 'G_bStopThread' anzeigen. auch die, die der thread benutzt
-
Aus dem CommandWindow - Immediate
&G_bStopThread 0x006b1230 bool volatile G_bStopThread &G_bStopThread 0x006b1230 bool volatile G_bStopThread
Das obere aus dem Thread, das untere bei OnKeyDown. Zudem ich weiss selber, dass ich keine zweite Variable definiert habe, welche so heisst. Es hat in diesem Programm nicht mal eine andere Variable die mit G_ anfängt ^^
Grüssli
-
okay, und wie siehts mit der initialisierung von 'G_bStopThread' aus. kann es sein dass die mehrmals stattfindet? irgendwas kann die wieder auf 'false' setzen? vielleicht ein wilder pointer?
ach ja, mach mal ein komplettes rebuild von dem projekt (auch alle vorher erzeugten .obj dateien löschen). die m$ ide's kriegen manchmal was nicht mit.
-
Komplett rebuild hat nix gebracht. Hab das schon selber probiert -> Immer wenn das Problem völlig unlogisch ist komplett rebuild machen, vielleicht funktioniert es dann. Leider isses hier nicht der Fall.
G_bStopThread wird nicht mehrmals initialisiert. Und wenn, dann immer auf true. Der Wert wird nur an einem Punkt auf false gesetzt, dass ist beim Threadstart, allerdings noch im Mainthread.
Ein wilderpointer ist es sicherlich auch nicht. Schon nur weil ich nie irgend ein Pointer auf G_bStopThread übergebe oder sonst wie mit seinem Pointer arbeite. Zudem, dass Problem tratt ja auch mit CEvent auf, nicht vergessen! ^^Ich probier jetzt mal die Messageschlaufe einzubauen. Hab dazu ein paar MSDN Artikel gelesen und denke ich könnte das implementieren. Doch so ganz zufrieden wäre ich damit nicht. Erstens möchte ich lernen die CEvents zu benutzen, zweitens befürchte ich grössere Einbusen in der Geschwindigkeit meines Threads, wenn ich immer zuerst nach Nachrichten durchsuche. Hat ein Thread nicht auch selbsterzeugte Nachrichten, die müsste ich dann nämlich auch abarbeiten, was zu Verzögerungen kommt.
Grüssli
-
naja, das mit der globalen variablen muss eigentlich funktionieren. erst recht, wenn die 'volatile' ist. bestimmt machst du irgendwas anderes falsch, z.b. editierst eine datei, compilierst aber eine andere...
-
hmm,
ich hab in einen Beispiel gesehen dass das WaitForSingleObject() nach dem AfxBeginThread() aufgerufen worden ist, kannst du es dort positionieren??m_pEvent = new CEvent(FALSE, TRUE); AfxBeginThread(ThreadFunc, (LPARAM)m_pEvent); // dann hier in der selben Funktion: WaitForSingleObject(...);
versuch mal, vielleicht hilfts!
lg
pixel
-
Jetzt habe ich grad was ganz seltsames entdeckt ^^
Ich habe nun das mit dem PostThreadMessage eingeführt. Es funktioniert nicht. Aber nur im normalen Betrieb nicht. Hmmm mal schauen wie ich das erkläre ^^if(nChar == VK_ESCAPE && m_pThread != NULL) { m_pThread->PostThreadMessage(Global::WM_THREADEND, 0, 0); // G_bStopThread = true; }
Das steht aktuelle in OnKeyDown. Wenn ich einen Breakpoint auf m_pThread->PostThreadMessage(...) setze, dann kann ich Escape im Programm drücken soviel wie ich will, es wird nie stoppen. Wenn ich den Breakpoint auf der if-Anweisung setze und im Programm Escape drücke, dann wird der Breakpoint aufgerufen. Wenn ich dann F10 drücke für den nächsten Schritt, geht er auch in die Anweisung rein, postet die Message und beendet dann den Thread.
Kann mir dies nun jemand erklären? ^^
[Edit]
@Pixel, worauf soll denn dort gewartet werden? Und wie lange? Auf den Thread oder das Event? Und wieso soll überhaupt im Mainthread gewartet werden. Der hat anderes zu tun, nämlich auf Input des Users zu warten. Z.b. ob der Escape drückt
[/Edit]Grüssli
-
Dravere schrieb:
@connan
Und wenn keine Nachricht wartet? Also wie kann ich meinen Threadcode mit dem abrufen der Nachrichten kombinieren?Du kannst deinen Code z.B. vor dem Ende der Schleife einfügen.
-
connan schrieb:
Dravere schrieb:
@connan
Und wenn keine Nachricht wartet? Also wie kann ich meinen Threadcode mit dem abrufen der Nachrichten kombinieren?Du kannst deinen Code z.B. vor dem Ende der Schleife einfügen.
Danke hab es schon selber rausgefunden, wie man es eigentlich aus meinem letzten Post herauslesen könnte
Aber das Problem besteht wie gesagt immer noch, bzw. inzwischen habe ich das Gefühl es liegt an was anderem, aber kann es wie gesagt nicht definieren. Schaut euch die Beschreibung meines letzten Posts an und sagt mir, was euch dazu einfällt ^^Grüssli
-
erstelle ein neues projekt und kopier deine bestehenden codes da rein. nur ein versuch auf doof, aber vielleicht geht das.
-
net schrieb:
erstelle ein neues projekt und kopier deine bestehenden codes da rein. nur ein versuch auf doof, aber vielleicht geht das.
Ist das ernst gemeint oder muss ich das als Witz auffassen? 0o ...
Wieso sollte das was ändern? Und ihr wollt mir doch nicht verklickern, dass ihr da auch nicht weiter wisst? Ihr seid doch meine Vorbilder, die Allwissenden, während ich nur der Neuling bin, dass könnt ihr mir doch nicht antun...
Grüssli
-
Dravere schrieb:
Ist das ernst gemeint oder muss ich das als Witz auffassen? 0o ...
ist ernst gemeint. sowas hilft, wenn irgendwelche projektdateien kaputt sind.