Join fachinformatiker.de Forum Now
Ergebnis 1 bis 11 von 11

WaitForMultipleObjects

Diskussion über WaitForMultipleObjects in C++: Compiler, IDEs, APIs der Kategorie Programmierung; Hallo an alle, ich starte mehrere Threads, möchte auf alle warten und die Exitcodes abfragen. Auch geht es mir darum ...

  1. #1
    Reg.-Benutzer Avatar von Narf!
    Reg.-Datum
    01.10.2002
    Ort
    Leipzig
    Beiträge
    431

    Standard WaitForMultipleObjects

    Hallo an alle,

    ich starte mehrere Threads, möchte auf alle warten und die Exitcodes abfragen.

    Auch geht es mir darum alle Thread-Handles zu löschen, da m_bAutoDelete=false gesetzt wird, sonst komme ich nicht an die Exitcodes.

    Im Moment sieht das so aus:

    Code:
    HANDLE *hAll=new HANDLE[dlg->m_cListCtrl_Jobs.GetItemCount()];
    
    //Für jeden Auftrag einen Thread starten
    for(int job=0; job<=dlg->m_cListCtrl_Jobs.GetItemCount()-1; job++)
     {
      CWinThread* thr=AfxBeginThread(ThrDoTheJobs, &dlg, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED, NULL);
    
      thr->m_bAutoDelete=false;
    
      hAll[job]=thr->m_hThread;
    
      thr->ResumeThread();
     }//end for(int job=0; job<=dlg->m_cListCtrl_Jobs.GetItemCount()-1; job++)
    
    //Auf alle Threads warten
    WaitForMultipleObjects(dlg->m_cListCtrl_Jobs.GetItemCount(), hAll, TRUE, INFINITE);
    
    //ExitCodes aller Threads abfangen, hier erstmal nur einer
    DWORD dwExitCode=0;
    
    GetExitCodeThread(hAll[0], &dwExitCode);
    
    CloseHandle(hAll);
    
    delete hAll;
    Da ich bisher nur mit einer bekannten Anzahl von Threads gearbeitet habe, also auf jeden einzelnen warten konnte, habe ich etwas Muffensausen.


    Don't know what you don't know, only know what you know.
    Der Mensch hat Maschinen gebaut, jetzt muss er damit leben.

  2. #2
    Administrator + Moderator
    C++: Compiler, IDEs, APIs / C und C++, Algorithmik, Basic, Sonstige, .NET
    Avatar von Klotzkopp
    Reg.-Datum
    10.07.2001
    Ort
    Essen
    Beiträge
    9.413

    Standard

    Das sieht schon gar nicht schlecht aus. Allerdings schließt du so nur das Handle des ersten Threads. Und wenn du new[] benutzt, musst du auch delete[] benutzen. Eine Klasse, die das ausnahmesicher mit RAII kapselt, wäre natürlich noch besser.
    "Funktioniert nicht" ist keine ausreichende Problembeschreibung.

  3. #3
    Reg.-Benutzer Avatar von Narf!
    Reg.-Datum
    01.10.2002
    Ort
    Leipzig
    Beiträge
    431

    Standard

    Zitat Zitat von Klotzkopp Beitrag anzeigen
    Allerdings schließt du so nur das Handle des ersten Threads.
    Also wieder eine for-Schleife, darin CloseHandle(hAll[job]).

    Zitat Zitat von Klotzkopp Beitrag anzeigen
    Eine Klasse, die das ausnahmesicher mit RAII kapselt, wäre natürlich noch besser.
    RAII: Was'n das?

    Don't know what you don't know, only know what you know.
    Der Mensch hat Maschinen gebaut, jetzt muss er damit leben.

  4. #4
    Administrator + Moderator
    C++: Compiler, IDEs, APIs / C und C++, Algorithmik, Basic, Sonstige, .NET
    Avatar von Klotzkopp
    Reg.-Datum
    10.07.2001
    Ort
    Essen
    Beiträge
    9.413

    Standard

    Ressourcenbelegung ist Initialisierung

    In C++ haben Variablen eine klar definierte Lebensdauer. Wenn der Gültigkeitsbereich einer Variable endet, wird sie zerstört. Bei Klassen bedeutet das, dass der Destruktor aufgerufen wird. Das passiert übrigens auch dann, wenn eine Ausnahme geworfen wird, die den Gültigkeitsbereich der Variablen verlässt. Wenn man nun solche Ressourcen wie Handles, die man explizit wieder freigeben muss, an eine Klasse koppelt, die genau das Freigeben im Destruktor übernimmt, kann man das Freigeben nicht mehr vergessen. Das Handle wird automatisch freigegeben, sobald das Objekt, das es kapselt, seinen Gültigkeitsbereich verlässt.

    Man kann also problemlos vorzeitig aus Funktionen herausspringen oder Ausnahmen werfen, und muss sich nicht mehr darum sorgen, ob alle angeforderten Ressourcen ordentlich freigegeben werden, weil das ganz automatisch passiert.

    Auf diesem Prinzip beruhen in C++ die Smartpointer. Das ist auch der Grund, warum man fstream::close normalerweise nicht braucht.

    Grundsätzlich wäre hier ein std::vector<HANDLE> besser als ein rohes Array, denn dann kannst du das delete[] weglassen und somit nicht mehr vergessen.

    Um das CloseHandle auch noch zu kapseln, musst du etwas tiefer in die Trickkiste greifen:
    Wenn du Visual C++ 2010 hast (da wird schon ein Teil des neuen Standards unterstützt), könntest du statt einem rohen HANDLE-Array einen std::vector<std::shared_ptr<HANDLE>> benutzen. Allerdings kannst du da nicht direkt die HANDLEs so "am Stück" rausholen, wie du es für WaitForMultipleObjects brauchst.
    Eine andere Möglichkeit wäre der ptr_vector von boost.
    "Funktioniert nicht" ist keine ausreichende Problembeschreibung.

  5. #5
    Reg.-Benutzer Avatar von Narf!
    Reg.-Datum
    01.10.2002
    Ort
    Leipzig
    Beiträge
    431

    Standard

    Aha, naja. Da ich Visual C++ 2003 nutze mache ich das wohl eher wie bisher. Wenn ich irgendwo auf das Schließen achten muss, dann schreibe ich gleich nach dem Öffnen als nächstes das Schließen und weiteren Quellcode dazwischen.

    Im Moment läuft alles prima, habe aber ein neues Problem:

    Beim Beenden erhalte ich die Warnung eines Speicherlecks.
    Code:
    Detected memory leaks!
    Dumping objects ->
    thrdcore.cpp(311) : {303} client block at 0x00BC3F08, subtype c0, 64 bytes long.
    a CWinThread object at $00BC3F08, 64 bytes long
    thrdcore.cpp(311) : {290} client block at 0x00BC3450, subtype c0, 64 bytes long.
    a CWinThread object at $00BC3450, 64 bytes long
    Object dump complete.
    Ich nehme mal an, das sind die beiden (da zwei Jobs) CWinThread *thr aus der ersten for-Schleife. Wie kriege ich die gelöscht?

    Kann ich da auch ein Array CWinThread[x] nehmen und thr[x]->Delete() aufrufen?

    Don't know what you don't know, only know what you know.
    Der Mensch hat Maschinen gebaut, jetzt muss er damit leben.

  6. #6
    Administrator + Moderator
    C++: Compiler, IDEs, APIs / C und C++, Algorithmik, Basic, Sonstige, .NET
    Avatar von Klotzkopp
    Reg.-Datum
    10.07.2001
    Ort
    Essen
    Beiträge
    9.413

    Standard

    Zitat Zitat von Narf! Beitrag anzeigen
    Wenn ich irgendwo auf das Schließen achten muss, dann schreibe ich gleich nach dem Öffnen als nächstes das Schließen und weiteren Quellcode dazwischen.
    Das ist aber nicht sicher. Erstens musst du immer daran denken, wenn du irgendwo ein vorzeitiges return einbaust, und zweitens funktioniert das nicht, sobald irgendwo dazwischen eine Exception fliegt.

    Solides C++ sieht anders aus.

    Zitat Zitat von Narf! Beitrag anzeigen
    Ich nehme mal an, das sind die beiden (da zwei Jobs) CWinThread *thr aus der ersten for-Schleife.
    Genau.

    Zitat Zitat von Narf! Beitrag anzeigen
    Kann ich da auch ein Array CWinThread[x] nehmen und thr[x]->Delete() aufrufen?
    Es sollte schon ein Array von CWinThread* sein.
    "Funktioniert nicht" ist keine ausreichende Problembeschreibung.

  7. #7
    Reg.-Benutzer Avatar von Narf!
    Reg.-Datum
    01.10.2002
    Ort
    Leipzig
    Beiträge
    431

    Standard

    Na gut, dann werde ich das mal solide machen.

    Und danke für die Hilfe.

    Don't know what you don't know, only know what you know.
    Der Mensch hat Maschinen gebaut, jetzt muss er damit leben.

  8. #8
    Reg.-Benutzer Avatar von Narf!
    Reg.-Datum
    01.10.2002
    Ort
    Leipzig
    Beiträge
    431

    Standard

    Es leckt noch immer.

    Es sieht jetzt so aus:

    Code:
    std::vector <CWinThread*> vecThr(dlg->m_cListCtrl_Jobs.GetItemCount());
    
    //Für jeden Server einen Thread starten
    for(int job=0; job<=dlg->m_cListCtrl_Jobs.GetItemCount()-1; job++)
     {
      vecThr.at(job)=AfxBeginThread(ThrDoTheJob, dlg, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED, NULL);
    
      vecThr.at(job)->m_bAutoDelete=false;
    
      hAll[job]=vecThr[job]->m_hThread;
    
      vecThr.at(job)->ResumeThread();
     }//end for(int job=0; job<=dlg->m_cListCtrl_Jobs.GetItemCount()-1; job++)
    
    ...
    
     //ExitCodes aller Threads abfangen
     for(int job=0; job<=dlg->m_cListCtrl_Jobs.GetItemCount()-1; job++)
      {      
       ...        
       vecThr.at(job)->Delete();
      }//end for(int job=0; job<=dlg->m_cListCtrl_Jobs.GetItemCount()-1; job++)

    Don't know what you don't know, only know what you know.
    Der Mensch hat Maschinen gebaut, jetzt muss er damit leben.

  9. #9
    Administrator + Moderator
    C++: Compiler, IDEs, APIs / C und C++, Algorithmik, Basic, Sonstige, .NET
    Avatar von Klotzkopp
    Reg.-Datum
    10.07.2001
    Ort
    Essen
    Beiträge
    9.413

    Standard

    Wo ist denn CloseHandle geblieben?

    Nebenbei: vector::at brauchst du nur, wenn du willst, dass eine Bereichsprüfung auf dem Index stattfindet. Du kannst einfach [] benutzen, wie du es beim Zugriff auf m_hThread getan hast.
    "Funktioniert nicht" ist keine ausreichende Problembeschreibung.

  10. #10
    Reg.-Benutzer Avatar von Narf!
    Reg.-Datum
    01.10.2002
    Ort
    Leipzig
    Beiträge
    431

    Standard

    CloseHandle(hAll[job]) kommt nach dem GetExitCode. Habe ich hier mit ... gekürzt.

    Bei CloseHandle(vecThr[job]->m_hThread) übergebe ich ein ungültiges Handle. Ob vor oder nach vecThr[job]->Delete() ist egal.

    Don't know what you don't know, only know what you know.
    Der Mensch hat Maschinen gebaut, jetzt muss er damit leben.

  11. #11
    Reg.-Benutzer Avatar von Narf!
    Reg.-Datum
    01.10.2002
    Ort
    Leipzig
    Beiträge
    431

    Standard

    Es leckt nicht mehr:

    Code:
    ...
        std::vector<CWinThread*>::iterator it1 = vecThr.begin();
    
        std::vector<CWinThread*>::iterator it2 = vecThr.end();
    
        while ( it1 != it2 )
         {
          delete *it1;
        
          ++it1;
         }
    ...

    Don't know what you don't know, only know what you know.
    Der Mensch hat Maschinen gebaut, jetzt muss er damit leben.

Aktive Benutzer

Aktive Benutzer

Aktive Benutzer in diesem Thema: 1 (Registrierte Benutzer: 0, Gäste: 1)