2010-07-05 4 views
5

Ich benutze Multithreading in meiner Anwendung mit _beginthread und jetzt zu warten, bis alle Threads fertig sind Ich habe globale Bools, die auf True festgelegt werden, da jeder Thread abgeschlossen ist, also bin ich in einer while-Schleife bis dahin. Es muss einen saubereren Weg geben, dies zu tun?Korrekte Art zu überprüfen, ob Threads ausgeführt werden?

Dank

Antwort

8

Sie WaitForMultipleObjects verwenden können, zu warten, die Fäden in primärem Thread zu beenden.

+0

Wenn Sie nur eine Thread-ID haben, müssen Sie diese zuerst in ein HANDLE konvertieren, indem Sie [OpenThread] aufrufen (https://msdn.microsoft.com/en-us/library/windows/desktop/ms684335 (v = vs .85) .aspx). – rustyx

+2

Nein, nicht OpenThread aufrufen! Wenn der Thread bereits beendet wurde und die ID neu zugewiesen wurde, könnten Sie mit einem Handle für einen anderen zufälligen Thread enden. Verwenden Sie _beginthreadex, das ein Handle für den Thread zurückgibt. (_beginthread gibt auch ein Handle zurück, aber (unter Angabe der Dokumente) "könnte ungültig sein oder auf einen anderen Thread verweisen". Verwenden Sie niemals _beginthread.) – benrg

3

Was Sie ist Thread Synchronisationstechniken einen Blick haben wollen - zum Glück gibt es einiges an Informationen über MSDN, die wahrscheinlich Ihnen helfen kann. Es ist wahrscheinlich, dass Sie Events und WaitHandles verwenden möchten, hier sind die wichtigsten Dinge auf MSDN: http://msdn.microsoft.com/en-us/library/ms681924%28v=VS.85%29.aspx gibt es eine Reihe von Beispielen.

Es gibt auch einige Informationen über die Synchronisation in MFC (die nicht als hilfreich erweisen kann oder nicht, zu Referenzzwecken hinzugefügt): http://msdn.microsoft.com/en-us/library/975t8ks0%28VS.71%29.aspx

Ich habe ein bisschen suchen getan, aber ich habe eine harte Zeit habe versucht, um einige hilfreiche Informationen für Sie zu finden, die die MFC-Implementierung nicht verwenden. Es gibt ein gutes Tutorial hier (http://www.informit.com/library/content.aspx?b=Visual_C_PlusPlus&seqNum=149), aber wieder mit MFC. Sie können sich jedoch zunächst die MFC-Implementierung von Mutexen ansehen.

So müssen Sie vertraut mit Synchronisationsfunktionen und Strukturen erhalten - alle hier auf MSDN abgedeckt: http://msdn.microsoft.com/en-us/library/ms686679%28v=VS.85%29.aspx

+0

Sie müssen auf jeden Fall Ereignisse über Bools verwenden. – DanDan

2

Verwenden Sie stattdessen _beginthreadex. Sowohl _beginthread als auch _beginthreadexreturn a thread handle, aber der Thread, der mit _beginthread gestartet wurde, schließt automatisch seinen Griff, wenn es fertig ist, so dass es für die Synchronisation nicht zuverlässig ist.

Der Thread-Handle kann mit einer der Synchronisierungsfunktionen von Win32 verwendet werden, z. B. WaitForSingleObject oder WaitForMultipleObjects.

Anschließend müssen die von _beginthreadex zurückgegebenen Handles mit CloseHandle() geschlossen werden.

0

Windows stellt Ereignisse für einen Thread bereit, um einen anderen zu benachrichtigen. Out-of-the-Box bietet Visual C++ Unterstützung für Ereignisse nur innerhalb von MFC. Für eine portable, nicht MFC-Version, überprüfen Sie die thread management classes der Boost-Bibliothek. Sie erleichtern das Starten und Warten auf Threads, bieten jedoch keinen direkten Zugriff auf alle Funktionen der Windows-API.

1

Die übliche Methode besteht darin, alle Thread-Handles beizubehalten und dann auf jeden Handle zu warten. Wenn der Handle signalisiert ist, ist der Thread beendet, so dass er aus der Gruppe der Threads entfernt wird. Ich verwende std::set<HANDLE>, um die Thread-Handles zu verfolgen. Es gibt zwei verschiedene Methoden zum Warten auf mehrere Objekte in Windows:

  1. Iterate über die Menge und rufen WaitForSingleObject mit einem Timeout auf jedem
  2. Konvertieren des Satzes in ein Array oder Vektor und rufen WaitForMultipleObjects

Das erste klingt ineffizient, aber es ist tatsächlich das direkteste und am wenigsten fehleranfällige der beiden.Wenn Sie für alle Threads warten müssen, dann verwenden Sie die folgende Schleife:

std::set<HANDLE> thread_handles; // contains the handle of each worker thread 
while (!thread_handles.empty()) { 
    std::set<HANDLE> threads_left; 
    for (std::set<HANDLE>::iterator cur_thread=thread_handles.begin(), 
            last=thread_handles.end(); 
     cur_thread != last; ++cur_thread) 
    { 
     DWORD rc = ::WaitForSingleObject(*cur_thread, some_timeout); 
     if (rc == WAIT_OBJECT_0) { 
      ::CloseHandle(*cur_thread); // necessary with _beginthreadex 
     } else if (rc == WAIT_TIMEOUT) { 
      threads_left.add(cur_thread); // wait again 
     } else { 
      // this shouldn't happen... try to close the handle and hope 
      // for the best! 
      ::CloseHandle(*cur_thread); // necessary with _beginthreadex 
     } 
    } 
    std::swap(threads_left, thread_handles); 
} 

WaitForMultipleObjects Verwendung für die Fäden bis zum Ende zu warten, ist ein bisschen schwieriger als es klingt. Das Folgende wird auf alle Threads warten; es wartet jedoch nur auf WAIT_MAXIMUM_OBJECTS Threads gleichzeitig. Eine andere Möglichkeit besteht darin, jede Seite von Threads zu durchlaufen. Ich werde diese Übung dem Leser überlassen;)

DWORD large_timeout = (5 * 60 * 1000); // five minutes 
std::set<HANDLE> thread_handles; // contains the handle of each worker thread 
std::vector<HANDLE> ary;   // WaitForMultipleObjects wants an array... 
while (!thread_handles.empty()) { 
    ary.assign(thread_handles.begin(), thread_handles.end()); 
    DWORD rc = ::WaitForMultipleObjects(std::min(ary.size(), WAIT_MAXIMUM_OBJECTS), 
             &ary[0], FALSE, large_timeout); 
    if (rc == WAIT_FAILED) { 
     // handle a failure case... this is usually something pretty bad 
     break; 
    } else if (rc == WAIT_TIMEOUT) { 
     // no thread exited in five minutes... this can be tricky since one of 
     // the threads beyond the first WAIT_MAXIMUM_OBJECTS may have terminated 
    } else { 
     long idx = (rc - WAIT_OBJECT_0); 
     if (idx > 0 && idx < ary.size()) { 
      // the object at `idx` was signaled, this means that the 
      // thread has terminated. 
      thread_handles.erase(ary[idx]); 
      ::CloseHandle(ary[idx]); // necessary with _beginthreadex 
     } 
    } 
} 

Das ist nicht gerade hübsch, aber es sollte funktionieren. Wenn Sie darauf vertrauen, dass alle Threads beendet werden und es Ihnen nichts ausmacht, auf sie zu warten, können Sie WaitForMultipleObjects(ary.size(), &ary[0], TRUE, INFINITE) verwenden. Dies ist normalerweise nicht sehr sicher, da ein Runaway-Thread Ihre Anwendung dazu bringt, unbegrenzt zu blockieren und es funktioniert nur, wenn ary.size() weniger als MAXIMUM_WAIT_OBJECTS ist.

Natürlich ist die andere Option, eine Thread-Pool-Implementierung zu finden und stattdessen zu verwenden. Das Schreiben von Threading-Code macht nicht wirklich viel Spaß, besonders wenn man es einmal in freier Wildbahn unterstützen muss. Verwenden Sie stattdessen etwas wie boost::thread_group.

0

Sie können boost :: thread Objekte verwenden. Rufen Sie join für das Objekt auf, und es wird auf das Ende des Threads warten.

Verwandte Themen