WaitForSingleObject Problem



  • 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.


  • Mod

    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");
    

  • Mod

    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...



  • net schrieb:

    insofern scheint jochens variante doch die einzig gute zu sein...

    😃


  • Mod

    Jochen Kalmbach schrieb:

    net schrieb:

    insofern scheint jochens variante doch die einzig gute zu sein...

    😃

    Wie gut, dass ich den Einwurf noch gemacht habe, damit Du diesen Auftritt bekommst <gd&rvvf>...


Anmelden zum Antworten