Fang Ausnahme vom worker-thread in den Haupt-thread
Habe ich nicht, eine schlüssige Antwort zu dem folgenden problem:ich habe eine Erzeuger - Verbraucher-threading-Modell aus, in dem Haupt-thread ist der Verbraucher während einige worker-thread ist der Produzent.Der Erzeuger-thread ausgeführt wird, es ist thread-Schleife während der Ausführung der Anwendung und es ist möglich, dass es Ausnahmen gelegentlich.Der Haupt-thread UI-thread, die sollten pop-up-Ausnahme-Nachrichten, einschließlich diejenigen, die aus verschiedenen threads. Wie kann ich diese abfangen von Ausnahmen in main thread?
Verwendung von boost unter Windows mit C++0x
WorkerThread.cpp
WorkerThread::WorkerThread(){
m_thread = boost::thread(&WorkerThread::drawThread,this);
}
void WorkerThread::drawThread()
{
while(true)
{
boost::unique_lock<boost::mutex> lock(m_mutex);
try{
///some work is done here...
}catch(std::exception &e){
///some exception is thrown
///notify main thread of the exception
}
}
}
Wichtig zu beachten, dass ich keine Möglichkeit zum wickeln WorkerThread in der main-thread mit try{}catch, wie es erstellt wird an einem gewissen Punkt und von da an läuft auf seine eigene, bis der Programmabbruch.
- Liebes internet, Sie brauchen nicht zu verwenden
bind
mitthread
. Nur sagenm_thread = boost::thread(&WorkerThread::drawThread, this);
- Danke für den Tipp 🙂
Du musst angemeldet sein, um einen Kommentar abzugeben.
Erstens, Sie brauchen nicht zu verwenden
bind
mitthread
. Dabei fügt nur unnötiges kopieren und macht den code schwerer zu Lesen. Ich wünschte, jeder würde aufhören.Können Sie speichern eine Ausnahme in einer
exception_ptr
- und übergeben, den anderen thread, z.B. instd::queue<std::exception_ptr>
:Dann in dem anderen thread rethrow es und behandeln es:
Wenn Sie nicht verwenden können
std::exception_ptr
Boost hat seine eigene Implementierung, aber ich bin mir nicht sicher, was die Boost-äquivalentcurrent_exception
ist. Müssen Sie möglicherweise wickeln Sie die Ausnahme in einem anderen Objekt, also die Boost-exception-propagation-Mechanismus kann es speichern.Möchten Sie vielleicht einen separaten mutex für die exception-queue aus dem Haupt-Werk-Schleife (und bewegen die
m_mutex
Sperre innerhalb dertry
block), je nachdem, wie langem_mutex
ist in der Regel verschlossen durch den worker-thread.Einen anderen Ansatz nutzt C++11-futures, die handle übergeben Ausnahmen zwischen threads mehr bequem. Benötigen Sie eine Möglichkeit für den Haupt-thread um eine Zukunft für jede Einheit der Arbeit ist der worker-thread läuft, was getan werden kann, mit
std::packaged_task
:Wenn der task ausgeführt wird, alle Ausnahmen gefangen werden, gespeichert in einem
exception_ptr
und solange gehalten, bis das Ergebnis Lesen Sie über die damit verbundene Zukunft.Den producer-thread ablegen konnten die
future
- Objekte in einer Warteschlange bei der Buchung der Arbeit an den Verbraucher, und einige andere Stück code, das überprüfen könnte, jede Zukunft in der Warteschlange, um zu sehen, wenn es fertig ist-und nennenget()
zu behandeln, ohne Ausnahme.packaged_task
. Menschen springen auf blankemstd::thread
viel zu schnell, wenn Sie für viele Zwecke ist es eigentlich zu low-level.post
ing erforderlich ist, fangen die Ausnahmen, nicht wahr? zz.. Btw, ich denke, dieser Ansatz ist sehr ähnlich zuboost::asio::io_service::work
post
können nur werfen eine exception, wenn der Speicherreservierung ein Fehler Auftritt, während der Erstellung derpackaged_task
oder hinzufügen, um die Warteschlange. Die Aufgabe wird in derdrawThread
, so dass eine Ausnahme passiert es und ist gefangen von derpackaged_task
gespeichert und in derfuture
.unique_lock
? Brauchen Sie für eine Aufschiebung der Sperre? Loslassen oder früh? Oder verschieben es auf ein anderes Objekt? Wenn nicht, warum verwenden die komplizierteren Sperre geben?lock_guard
nur verriegelt und entriegelt, nichts mehr, und das ist der gesamte code, der benötigt wird.std::exception_ptr
werden kann erneut ausgelöst, später, und wird die ursprüngliche Ausnahme, ohne es zu verändern. Wenn Sie speicherne
du dann nur speichernstd::exception
Objekt erstellt durch schneiden. Wenn die ursprüngliche Ausnahme war einstd::runtime_error
dann verlieren Sie diese Informationen, und speichern Sie die in Scheiben geschnittenen Kopie der Basis-Klasse des Typsstd::exception
. Wenn Sie speichern einestd::exception_ptr
es ist kein kopieren, kein schneiden und kein Verlust von Informationen.Diese Antwort schlage vor, Sie senden
exception_ptr
zum Haupt-thread manuell. Das ist nicht so schlimm, aber ich schlage vor, Sie einen anderen Weg:std::promise
/boost::promise
.(Da ich nicht haben, steigern Sie in diesem computer nun, so geh ich mit
std::promise
. Jedoch gibt es möglicherweise keinen großen Unterschied mit boost.)Suchen Sie den Beispiel-code:
Der Vorteil dieser Art ist 1. Sie nicht haben, zu verwalten Ausnahmen manuell -
std::promise
undstd::future
alles tun und 2. Sie können alle Funktion umstd::future
. In diesem Fall, ich habe andere Dinge zu tun (bestenswaiting...
Nachricht) während der Wartezeit den thread beenden, durchstd::future::wait_for
.promise
ist, können Sie nur verwenden Sie es einmal, die Frage zeigt, abfangen von Ausnahmen in einer Schleife, was es braucht, um die Behandlung von Ausnahmen nach der erstenfuture
wäre für den Hersteller übergeben die Arbeit an den Verbraucher in form vonstd::packaged_task
Objekte, halten Sie hold einfuture
dass Aktien Staat mit jedem packaged_task. Auf diese Weise für jede Aufgabe posteed für den Verbraucher gibt es eine entsprechende Zukunft, und ein Kanal für immer die Ausnahmepackaged_task
In der worker-Threads, Sie können die Ausnahme abfangen, und dann rufen Sie einen
std::exception_ptr
mitstd::current_exception
. Sie können dann speichern Sie diese irgendwo, Holen es in der main-thread, und werfen Sie es mitstd::rethrow_exception
.std::exception_ptr
werden, übergeben Sie es aus dem Haupt-thread, und dann rethrow es.std::queue<std::exception_ptr>
bewacht von einem mutex wäre eine Möglichkeit.Ausnahmen sind synchron. Was bedeutet, es gibt keine Möglichkeit, Sie zu übergeben, die zwischen threads als Ausnahmen. Sie können nicht sagen, an irgendeinem alten thread "stoppen, was Sie tun und damit umgehen". (Gut Sie können, wenn Sie liefern ein POSIX-signal an, aber das ist nicht ganz eine C++ - Ausnahme).
Können Sie natürlich immer ein Objekt übergeben, mit Ausnahme der Daten (im Gegensatz zu dem Zustand des seins in einen exception-handling-Modus) zu einem anderen thread in der gleichen Weise, Sie würde passieren, alle anderen Daten zwischen threads. Eine concurrent queue zu tun. Dann Bearbeiten Sie es in die Ziel-thread. Die Ziel-thread sollte aktiv Lesen von Daten aus der Warteschlange.