Wie beende ich einen Thread in C ++ 11?

137

Ich muss den Thread nicht korrekt beenden oder auf einen "Beenden" -Befehl reagieren lassen. Ich bin daran interessiert, den Thread mit reinem C ++ 11 gewaltsam zu beenden.

Alexander V.
quelle
7
Hier ist eine gute Frage zu diesem Thema: stackoverflow.com/questions/2790346/c0x-thread-interruption "Alle Sprachspezifikationen besagen, dass die Unterstützung nicht in die Sprache integriert ist"
Nemanja Boric

Antworten:

137
  1. Sie können std::terminate()von jedem Thread aus aufrufen, und der Thread, auf den Sie sich beziehen, wird zwangsweise beendet.

  2. Sie können veranlassen ~thread(), dass die Ausführung für das Objekt des Zielthreads ausgeführt wird, ohne dass eine Intervention join()oder detach()für dieses Objekt erfolgt. Dies hat den gleichen Effekt wie Option 1.

  3. Sie können eine Ausnahme entwerfen, die einen Destruktor hat, der eine Ausnahme auslöst. Und veranlassen Sie dann, dass der Ziel-Thread diese Ausnahme auslöst, wenn sie zwangsweise beendet werden soll. Der schwierige Teil in diesem Fall besteht darin, dass der Ziel-Thread diese Ausnahme auslöst.

Die Optionen 1 und 2 verlieren keine prozessinternen Ressourcen, beenden jedoch jeden Thread.

Option 3 wird wahrscheinlich Ressourcen verlieren, ist jedoch teilweise kooperativ, da der Ziel-Thread zustimmen muss, um die Ausnahme auszulösen.

In C ++ 11 gibt es keine tragbare Möglichkeit (wie mir bekannt ist), einen einzelnen Thread in einem Multithread-Programm nicht kooperativ zu beenden (dh ohne alle Threads zu beenden). Es gab keine Motivation, ein solches Feature zu entwerfen.

A std::threadkann diese Mitgliedsfunktion haben:

native_handle_type native_handle();

Möglicherweise können Sie damit eine betriebssystemabhängige Funktion aufrufen, um das zu tun, was Sie möchten. Zum Beispiel unter Apples Betriebssystemen existiert diese Funktion und native_handle_typeist eine pthread_t. Wenn Sie erfolgreich sind, werden Sie wahrscheinlich Ressourcen verlieren.

Howard Hinnant
quelle
2
Leichte nitpick auf „nicht intra-Prozess Ressourcen Leck“ : Während es natürlich wahr ist , dass das Betriebssystem alle Ressourcen zurückzugewinnen, nachdem den Prozess zu töten, die Ressourcen sind durchgesickert , so weit das Programm betrifft. Das ist normalerweise irrelevant, kann aber in einigen Fällen immer noch ein Problem sein. std::terminateWeder werden statische Destruktoren aufgerufen, noch werden Ausgabepuffer geleert, sodass die Reihenfolge, in der Ressourcen freigegeben werden, nicht genau definiert ist. Sie können auch nicht garantieren, dass Ihre Daten für den Benutzer sichtbar sind oder in einen permanenten Speicher geschrieben werden oder sogar konsistent und vollständig.
Damon
6
Sie können auch aufrufen exit()oder abort()den gleichen Gesamteffekt erzielen.
n. 'Pronomen' m.
2
# 1 ist ein Witz und @ChrisDodd ist richtig. Der Witz wird in der Antwort im ersten Satz unter # 3 erklärt. Siehe auch die Antwort von Nanno Langstraat und die Kommentare darunter.
Howard Hinnant
43

@ Howard Hinnants Antwort ist sowohl richtig als auch umfassend. Aber es könnte missverstanden werden, wenn es zu schnell gelesen wird, weil std::terminate()(der gesamte Prozess) zufällig den gleichen Namen hat wie das "Beenden", das @AlexanderVX im Sinn hatte (1 Thread).

Zusammenfassung: "1 Thread beenden + gewaltsam (Ziel-Thread kooperiert nicht) + reines C ++ 11 = Auf keinen Fall."

Nanno Langstraat
quelle
14
Ahh, meine Nummer 1 ist wirklich lustig. Sie müssen nicht angeben, welchen Thread Sie zwangsweise beenden möchten. Das System weiß auf magische Weise, welches Sie mit Gewalt beenden möchten und tut es!
Howard Hinnant
8
Ja, die std::terminate()Antwort ist wie eine klassische schelmische Dschinn-Geschichte. es erfüllt alles im Wunsch des OP auf den Brief, wenn auch wahrscheinlich nicht so, wie er es meinte . Der zurückhaltende Humor brachte mich zum Lächeln. :-)
Nanno Langstraat
2
Sie müssen nur verhindern, dass unschuldige C ++ - Anfänger ihre Hoffnungen zu weit / zu lange aufkommen lassen.
Nanno Langstraat
2
Elegant gesagt. :-)
Howard Hinnant
@NannoLangstraat verdammt ... Ich hatte so große Hoffnungen, bis ich weiter las: (..lol, na ja + 1 ist überall
:)
13

Diese Frage hat tatsächlich einen tieferen Charakter und ein gutes Verständnis der Multithreading-Konzepte im Allgemeinen gibt Ihnen Einblick in dieses Thema. Tatsächlich gibt es keine Sprache oder kein Betriebssystem, das Ihnen die Möglichkeit bietet, einen asynchronen abrupten Thread-Abbruch ohne Warnung durchzuführen, diese nicht zu verwenden. Alle diese Ausführungsumgebungen empfehlen Entwicklern dringend oder erfordern sogar das Erstellen von Multithreading-Anwendungen auf der Basis einer kooperativen oder synchronen Thread-Beendigung. Der Grund für diese gemeinsamen Entscheidungen und Ratschläge ist, dass sie alle auf demselben allgemeinen Multithreading-Modell basieren.

Vergleichen wir Multiprozessor- und Multithreading-Konzepte, um die Vor- und Nachteile des zweiten besser zu verstehen.

Bei der Mehrfachverarbeitung wird die Aufteilung der gesamten Ausführungsumgebung in eine Reihe vollständig isolierter Prozesse vorausgesetzt, die vom Betriebssystem gesteuert werden. Der Prozess enthält und isoliert den Status der Ausführungsumgebung, einschließlich des lokalen Speichers des Prozesses und der darin enthaltenen Daten sowie aller Systemressourcen wie Dateien, Sockets und Synchronisationsobjekte. Isolation ist ein kritisch wichtiges Merkmal des Prozesses, da sie die Fehlerausbreitung durch die Prozessgrenzen begrenzt. Mit anderen Worten, kein Prozess kann die Konsistenz eines anderen Prozesses im System beeinflussen. Gleiches gilt für das Prozessverhalten, jedoch weniger eingeschränkt und unscharfer. In einer solchen Umgebung kann jeder Prozess in jedem "beliebigen" Moment beendet werden, da erstens jeder Prozess isoliert ist, zweitens

Im Gegensatz dazu setzt Multithreading voraus, dass mehrere Threads im selben Prozess ausgeführt werden. Alle diese Threads haben jedoch dieselbe Isolationsbox und es gibt keine Betriebssystemsteuerung für den internen Status des Prozesses. Infolgedessen kann jeder Thread den globalen Prozessstatus ändern und ihn beschädigen. Gleichzeitig hängen die Punkte, an denen der Status des Threads bekanntermaßen sicher ist, um einen Thread vollständig zu beenden, von der Anwendungslogik ab und sind weder für das Betriebssystem noch für die Laufzeit der Programmiersprache bekannt. Infolgedessen bedeutet das Beenden eines Threads zum beliebigen Zeitpunkt das Beenden des Threads an einem beliebigen Punkt seines Ausführungspfads und kann leicht zu prozessweiter Beschädigung der Daten, Speicher und Leckagen führen.

Aus diesem Grund besteht der übliche Ansatz darin, Entwickler zu zwingen, eine synchrone oder kooperative Thread-Beendigung zu implementieren, wobei der eine Thread eine andere Thread-Beendigung anfordern kann und ein anderer Thread an einem genau definierten Punkt diese Anforderung überprüfen und das Herunterfahren aus dem genau definierten Zustand starten kann mit der Freigabe aller globalen systemweiten Ressourcen und lokalen prozessweiten Ressourcen auf sichere und konsistente Weise.

ZarathustrA
quelle
7
Dies ist keine sehr hilfreiche Antwort. Multiverarbeitung ist hier nicht relevant, und die Beobachtungen zum Multithreading sind ziemlich weit gefasst.
MSalters
4
Was ich im Detail sagen und sagen wollte, ist, dass das Multithreading-Modell keine formale Möglichkeit zur erzwungenen Thread-Beendigung bietet. C ++ möchte den klaren Modellen folgen, einschließlich Speichermodell, Multithreading-Modell usw. Die Methode der erzwungenen Thread-Beendigung ist von Natur aus unsicher. Wenn das C ++ - Standardkomitee gezwungen wäre, es zu C ++ hinzuzufügen, würde es mit der nächsten Anweisung "Methode terminate () beendet die Thread-Ausführung. Verhalten undefiniert." Gemacht, was wie "etwas Magie machen und (möglicherweise) den Thread beenden" klingt ".
ZarathustrA
11

Tipps zur Verwendung der betriebssystemabhängigen Funktion zum Beenden des C ++ - Threads:

  1. std::thread::native_handle()Nur der gültige native Handle-Typ des Threads kann vor dem Aufruf von join()oder abgerufen werden detach(). Danach wird native_handle()0 zurückgegeben - pthread_cancel()wird coredump.

  2. Um die native Thread-Beendigungsfunktion (z. B. pthread_cancel()) effektiv aufzurufen , müssen Sie das native Handle speichern, bevor Sie std::thread::join()oder aufrufen std::thread::detach(). Damit Ihr nativer Terminator immer ein gültiges natives Handle verwendet.

Weitere Erklärungen finden Sie unter: http://bo-yang.github.io/2017/11/19/cpp-kill-detached-thread .

Boyang
quelle
5

Ich denke, der Thread, der getötet werden muss, befindet sich entweder in einem Wartemodus oder erledigt schwere Arbeit. Ich würde vorschlagen, einen "naiven" Weg zu verwenden.

Definieren Sie einen globalen Booleschen Wert:

std::atomic_bool stop_thread_1 = false;

Fügen Sie den folgenden Code (oder einen ähnlichen Code) in mehrere wichtige Punkte ein, sodass alle Funktionen im Aufrufstapel zurückgegeben werden, bis der Thread natürlich endet:

if (stop_thread_1)
    return;

So stoppen Sie den Thread von einem anderen (Haupt-) Thread:

stop_thread_1 = true;
thread1.join ();
stop_thread_1 = false; //(for next time. this can be when starting the thread instead)
Doron Ben-Ari
quelle