C ++: Aufruf ohne aktive Exception (GCC) beenden

8

Betrachten Sie das folgende Programm:

%Vor%

Dies läuft gut, solange keine Optimierung (oder -O1) verwendet wird, z. mit g ++ -std = c ++ 11 -Wall -o Test test.cc -thread

Mit -O2 oder -O3 bricht das Programm jedoch mit der obigen Meldung ab.

Auch irgendwie interessant: Es läuft durch, wenn es mit -DNOEXCEPT kompiliert wird. So scheint es, wenn ein Thread in einer Funktion abgebrochen wird, die möglicherweise [sic!] Eine Ausnahme auslöst, und wenn die Optimierung eingeschaltet ist, kann das Programm abbrechen. - Und ich sehe keinen Weg, das zu verhindern.

Es ist für mich reproduzierbar auf amd64 gcc 4.8.4 (Ubuntu 14.04.3) und armv7l gcc 4.9.2 (Raspbian 4.9.2-10).

Können Sie das reproduzieren? Hast du eine Erklärung? Dieses Verhalten scheint (zumindest für mich) seltsam zu sein. Ich würde mich über Feedback freuen. Danke!

    
mikro77 07.06.2016, 11:38
quelle

2 Antworten

2

Unter Linux (wie bei den meisten Betriebssystemen) sind Ausnahmen eine sprachunabhängige Funktion, und Pthread-Unterdrückung wird mit sprachunabhängigen Ausnahmen implementiert (siehe z. B. Cancellation und C ++ Ausnahmen ).

Wenn eine PThread-Annullierung an einen Thread geliefert wird (ein Signal verwendend, aber Sie müssen das nicht wissen), ruft die Abwicklungs-Maschinerie alle installierten Persönlichkeiten auf, so dass sie eine sprachspezifische Bereinigung durchführen können, bevor der Thread beendet wird. (Das ist ziemlich cool; es bedeutet, dass Sie wie im obigen Artikel einen catch-Block für abi::__forced_unwind einfügen können, um eine Thread-Löschung zu erkennen, aber nicht zu verhindern.)

Das Problem besteht darin, dass eine asynchrone Löschung bei jedem Befehl auftreten kann und die von g ++ generierten C ++ - Ausnahmetabellen nur mit Ausnahmen umgehen, die bei Anweisungen auftreten, von denen bekannt ist, dass sie Ausnahmen erzeugen können (d. h. Wenn eine Ausnahme an einem Punkt generiert wird, der nicht von den C ++ - Tabellen abgedeckt wird, wird die C ++ - Eigenschaft in Panik versetzt und beendet den Prozess (daher "terminate called ohne eine aktive Ausnahme").

Der Grund, warum dies durch die Optimierung beeinflusst wird, ist, dass die C ++ - Persönlichkeit träge installiert ist, aber bei höheren Optimierungsstufen könnte der Compiler entscheiden, die C ++ - Persönlichkeit präventiv zu installieren. Sie können den Absturz auch bei niedrigeren Optimierungsstufen durch Ausführen der C ++ - Ausnahme-Maschinerie, z. mit try { throw 0; } catch (int) {} .

Die einfachste Lösung besteht darin sicherzustellen, dass die C ++ - Kennung nicht in dem Thread installiert ist, den Sie asynchron abbrechen möchten. Sie können dies sicherstellen, indem Sie die Thread-Funktion als C kompilieren und keine C ++ - Funktionen davon aufrufen.

Eine mehr Hacky und hoch nicht unterstützte Lösung besteht darin, sicherzustellen, dass alle asynchronen Löschpunkte (dh alle Anweisungen, bei denen der abgebrochene Thread bei der asynchronen Löschung empfangen werden konnte) sind tatsächlich durch die C ++ - Abwicklungstabellen abgedeckt. Zuerst müssen Sie mit -fnon-call-exceptions ; Zweitens müssen Sie sicherstellen, dass jeder Befehl, der ein asynchroner Löschpunkt sein könnte, zwischen zwei Punkten ist, von denen bekannt ist, dass sie synchrone Löschpunkte sind, z. pthread_testcancel :

%Vor%     
ecatmur 07.06.2016, 17:32
quelle
-1
  

Jemand hat hier geschrieben, dass ein Programm abbricht "wenn ein Thread-Objekt seinen Gültigkeitsbereich verlässt und sich im verknüpfbaren Zustand befindet".

Das sagt 39.3.1.3/1 [thread destructor] eigentlich:

  

Wenn joinable (), ruft std :: terminate () auf. [...] Daher muss der Programmierer sicherstellen, dass der Destruktor niemals ausgeführt wird, solange der Thread noch verbindbar ist.

    
skypjack 07.06.2016 12:44
quelle