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:
- Iterate über die Menge und rufen
WaitForSingleObject
mit einem Timeout auf jedem
- 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
.
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
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