WaitForSingleObject Problem
-
Hallo,
ich probiere folgendes:// Hier werden alle Steuerelemente gesucht CWinThread* vgl_thread = AfxBeginThread(MASTER_scan_img, this); WaitForSingleObject(vgl_thread->m_hThread,INFINITE); MessageBox("jetzt");
Leider hängt sich das Programm immer auf bzw. reagiert nicht mehr.
Ich will eigentlich den Thread alle Steuerelemente suchen lassen und danach in meine Master-Funktion dem weiteren Ablauf folgen. Was mache ich falsch?Zur Erklärung: Ich arbeite an einem Tool, welches andere Programme testen soll und dazu muss mein Tool erst die Steuerelemente der anderen Tools erkennen.
Grüße,
Michael
-
offensichtlich wartet dein 'WaitForSingleObject' INFINITE
das kommt daher, dass sich der thread nicht beendet...
-
Wenn du MASTER_scan_img als Thread startest und sofort danach darauf wartest, dass der Thread terminiert, kannst du MASTER_scan_img auch direkt aufrufen. Beides bewirkt, dass dein Programm an dieser Stelle hängt, bis MASTER_scan_img fertig ist.
-
Das geht leider nicht, weil das scannen nahezu 100% Prozessoauslastung verursacht (das ist wirklich sehr rechenintensiv). Wenn ich diese Funktion nicht in einen separaten Thread auslagere, dann hängt sich das Programm schon auf, wenn man das Fenster mit der Maus verschiebt.
Der Thread ist also notwendig.
Zu 1.: Der Thread würde schon beenden. Er braucht ca. 1min für die gesamten Berechnungen. Das Programm reagiert schon nach 5 sek. nicht mehr. Außerdem ist die CPU-Auslastung nach dem Start auch bei nahezu 0% was nicht dafür spricht, dass der Scan-Thread richtig läuft.
-
Außerdem: Ich habe gerade mal das INFINITE auf 5 Sek geändert. Dann kommt nach den 5sek die MessageBox und erst dann startet der Thread. Sehr seltsam!
-
Hecker.Michael schrieb:
Wenn ich diese Funktion nicht in einen separaten Thread auslagere, dann hängt sich das Programm schon auf, wenn man das Fenster mit der Maus verschiebt.
Du hast nicht "ausgelagert". Du startest den Thread und wartest dann darauf, dass er fertig wird. Da läuft nichts parallel.
Der Thread ist also notwendig.
Mag sein. So, wie du ihn benutzt, bring er aber nichts.
Außerdem ist die CPU-Auslastung nach dem Start auch bei nahezu 0% was nicht dafür spricht, dass der Scan-Thread richtig läuft.
Dann machst du in dem Thread womöglich etwas falsch. Das kann mangels Code natürlich sonst niemand beurteilen.
-
Diese Funktion wird per Button gestartet
void CRobinHoodDlg::On_start() { // Hier werden alle Steuerelemente gesucht CWinThread* vgl_thread = AfxBeginThread(MASTER_scan_img, this); WaitForSingleObject(vgl_thread->m_hThread,INFINITE); }
Hier die MASTER_scan_img
UINT CRobinHoodDlg::MASTER_scan_img(LPVOID pParam) { CRobinHoodDlg* pDlg = (CRobinHoodDlg*) pParam; CString img_pfad,strPfad,url,datei; // Bestimmung des aktuellen Programmpfads trPfad = GetCommandLine(); // Dateierweiterung abschneiden int nPos = strPfad.ReverseFind( '\\'); strPfad = strPfad.Mid(1, nPos-1); // Der Ordner in dem die Vorlagen liegen img_pfad.Format("%s\\img",strPfad); bool alle_elemente_gefunden=true,suchen=true; while(suchen){ // Hier werden alle Steuerelemente gesucht for(int i=0;i<=pDlg->m_steuerelemente.GetItemCount();i++){ [...] pDlg->CRobinHoodDlg::scan_img("single",zeile); } } // Hier wird geprüft, ob alle Steuerelemente gefunden wurden [...] return true; }
Und hier die eigentliche Scan-Funktion
void CRobinHoodDlg::scan_img(CString Modus, int schreib_zeile) { [...] if(treffer==max_possible){ best_x=x1; best_y=y1; // Nachdem das erste Objekt gefunden wurde, wird die Suche abgebrochen if(Modus=="single"){ x1=1280+1; y1=768+1; } // Hier wird der Cursor auf die Position gesetzt, die gefunden wurde SetCursorPos(best_x+(vgl_width/2), best_y+(vgl_height/2)); } [...] }
-
Guck einfach mal mit dem Debugger wo der "scan" Thread steht während der main Thread auf ihn wartet. Ich denke mal der steht in einem SendMessage oder ähnlichem.
Wie: einfach "pause" drücken während das Programm im WaitForSingleObject steht, dann über "threads" auf den scan thread umschalten (falls du mit dem Debugger im main thread landest), und dann im call stack gucken wo der steckt.
-
CWinThread* vgl_thread = AfxBeginThread(MASTER_scan_img, this); WaitForSingleObject(vgl_thread->m_hThread,INFINITE);
BTW: Dieser Code muss auf längere Sicht hin zu vielen Fehlern führen.
1. Hier wird ein Thread gestartet und ein Thread Objekt returniert. Nur normalerweise wird genau dieses Objekt sofort vernichtet wenn der Thread terminiert. Der Zugriff auf wgl_thread->m_hThread ist also nicht gewährleistet wohin die Schose zeigt.
Im Extremfall, schmiert das Ding sofort ab wenn der Thread startet und sofort wieder beendet!
2. Das Objekt auf das hier gewartet wird, wird durch den Thread signalisiert und anschließend sofort geschlossen (durch CloseHandle). D.h. das Handle ist evtl. nicht mehr gültig auf das WaitForSingleObject wartet.Einzig korrekter Weg: AutoDelete im Thread auf False setzen! Und nach dem Warten selbst das Thread Objekt zerstören!
-
Martin Richter schrieb:
Einzig korrekter Weg: AutoDelete im Thread auf False setzen!
das muss der thread aber selber machen, sonst haste ja das gleiche problem...
-
net schrieb:
Martin Richter schrieb:
Einzig korrekter Weg: AutoDelete im Thread auf False setzen!
das muss der thread aber selber machen, sonst haste ja das gleiche problem...
Nein... mach es einfach so wie es in der MSDN-DOu steht:
dwCreateFlags
Specifies an additional flag that controls the creation of the thread. This flag can contain one of two values:
CREATE_SUSPENDED Start the thread with a suspend count of one. Use CREATE_SUSPENDED if you want to initialize any member data of the CWinThread object, such as m_bAutoDelete or any members of your derived class, before the thread starts running. Once your initialization is complete, use CWinThread::ResumeThread to start the thread running. The thread will not execute until CWinThread::ResumeThread is called.
-
Fazit:
CWinThread* vgl_thread = AfxBeginThread( MASTER_scan_img, this, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED, NULL ); vgl_thread->m_bAutoDelete = FALSE; vgl_thread->ResumeThread(); WaitForSingleObject(vgl_thread->m_hThread,INFINITE); delete vgl_thread; MessageBox("jetzt");
-
OK! So geht es natürlich auch und ist sicherlich auch klarer!
Danke für die Ergänzung ich vergesse das immer wieder!
-
Jochen Kalmbach schrieb:
Fazit:
CWinThread* vgl_thread = AfxBeginThread( MASTER_scan_img, this, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED, NULL ); vgl_thread->m_bAutoDelete = FALSE; vgl_thread->ResumeThread(); WaitForSingleObject(vgl_thread->m_hThread,INFINITE); delete vgl_thread; MessageBox("jetzt");
oder so:
CWinThread* vgl_thread = AfxBeginThread ( MASTER_scan_img, this, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED, NULL ); HANDLE hthread = vgl_thread->m_hThread; vgl_thread->ResumeThread(); WaitForSingleObject (hthread,INFINITE);
...aber ist ja beides recht fummelig. da drängt sich einem doch die frage auf, ob man nicht besser auf 'CWinThread' verzichtet und gleich winapi 'CreateThread' nimmt...
-
net schrieb:
oder so:
CWinThread* vgl_thread = AfxBeginThread ( MASTER_scan_img, this, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED, NULL ); HANDLE hthread = vgl_thread->m_hThread; vgl_thread->ResumeThread(); WaitForSingleObject (hthread,INFINITE);
NEIN! Das ist ja auch wieder falsch!!!
Du hast hier wieder das "m_bAutoDelete" vergessen...
Das "kopieren" des Thread-Handles bringt Dir nichts, wenn dieses Handle im automatisch ausgeführeten Destruktor innerhalb des Threads, geschlossen wird.
Somit würde dann dein Wait auf ein falsches Handle warten (was vermutlich auch als Fehlercode zurückkommt).
Das Wait wird AFAIK nie mit "WAIT_OBJECT_0" zurückkommen...PS: CWinThread hat schon seine Berechtigung, wenn Du z.B. mit Messages arbeiten willst... dann ist es mit CWinThread recht einfach.
-
Jochen Kalmbach schrieb:
NEIN! Das ist ja auch wieder falsch!!!
wieso? der thread wird 'suspended' erzeugt. dann kann er das 'CWinThread' objekt doch nicht löschen...
-
Du kopierst Dir doch nur das Handle (also den Wert)!
Wenn Du den Thread wieder laufen lässt, und er z.B. sich gleich beendet, dann hat er das Handle schon via CloseHandle geschlossen, bevor Du noch die Wait-Funktion aufruefen kannst. Der Zahlenwert in Deinem Handle mag ja noch stimmen, aber das Handle ist ungültig!Also ein kopieren eines Handlewertes hilft Dir nicht viel, wenn das Handle geschlossen wird...
Ok, Du könntest
HANDLE hthread = DuplicateHandle(..., vgl_thread->m_hThread, ...);
verwenden... aber jetzt wird es so langsam umständlich...
-
Jochen Kalmbach schrieb:
Wenn Du den Thread wieder laufen lässt, und er z.B. sich gleich beendet, dann hat er das Handle schon via CloseHandle geschlossen, bevor Du noch die Wait-Funktion aufruefen kannst.
das kann bei deinem code aber auch passieren...
-
net schrieb:
Jochen Kalmbach schrieb:
Wenn Du den Thread wieder laufen lässt, und er z.B. sich gleich beendet, dann hat er das Handle schon via CloseHandle geschlossen, bevor Du noch die Wait-Funktion aufruefen kannst.
das kann bei deinem code aber auch passieren...
Warum? Er setzt doch auto-delete auf false.
-
???????? schrieb:
Warum? Er setzt doch auto-delete auf false.
stimmt. hast recht
also sorgt 'autodelete' nicht nur dafür, dass der 'CWinThread' gelöscht wird, sondern macht auch noch ein 'CloseHandle' (musses ja auch).
insofern scheint jochens variante doch die einzig gute zu sein...