Frage

Was sind die Spannungen zwischen Multithreading und Ausnahme-Sicherheit in C ++? Gibt es gute Richtlinien zu folgen? Hat ein Thread aufgrund einer nicht erfassten Ausnahme beenden?

War es hilfreich?

Lösung

Ich glaube, der C ++ Standard macht keine Erwähnung von Multithreading - Multithreading ein plattformspezifisches Merkmal ist

.

Ich bin mir nicht ganz sicher, was der C ++ Standard sagt über abgefangene Ausnahmen im Allgemeinen, aber nach diese Seite , was passiert ist plattform definiert, und Sie sollten in Ihrem Compiler in der Dokumentation erfahren.

In einem schnellen und unsauberen Test, den ich mit g tat ++ 4.0.1 (i686-apple-darwin8-g ++ - 4.0.1 um genau zu sein), ist das Ergebnis, dass terminate() genannt wird, die das gesamte Programm tötet. Der Code, den ich verwendet folgt:

#include <stdio.h>
#include <pthread.h>

void *threadproc(void *x)
{
  throw 0;

  return NULL;
}

int main(int argc, char **argv)
{
  pthread_t t;
  pthread_create(&t, NULL, threadproc, NULL);

  void *ret;
  pthread_join(t, &ret);

  printf("ret = 0x%08x\n", ret);

  return 0;
}

Zusammengestellt mit g++ threadtest.cc -lpthread -o threadtest. Ausgang war:

terminate called after throwing an instance of 'int'

Andere Tipps

C ++ 0x haben Sprache Unterstützung für Ausnahmen zwischen Threads Transport so dass, wenn ein Arbeitsthread kann eine Ausnahme der Laich Faden wirft ihn fangen oder erneut auslösen.

Aus dem Vorschlag:

namespace std {

    typedef unspecified exception_ptr;

    exception_ptr current_exception();
    void rethrow_exception( exception_ptr p );

    template< class E > exception_ptr copy_exception( E e );
}

Eine abgefangene Ausnahme wird terminate() nennen, was wiederum die terminate_handler nennt (die durch das Programm eingestellt werden kann). Standardmäßig ruft die terminate_handler abort().

Auch wenn Sie den Standard-terminate_handler außer Kraft setzen, so der Standard, dass die Routine, die Sie zur Verfügung stellen (ISO 14882-2003 18.6.1.3).

„wird den Anrufer ohne Rückkehr Ausführung des Programms beenden“

So in der Zusammenfassung, eine abgefangene Ausnahme wird das Programm nicht nur der Thread beenden.

Was Thread-Sicherheit geht, wie Adam Rosenfield sagt, das ist eine Plattform-spezifische Sache, die von der Norm nicht angesprochen wird.

Dies ist der größte Grund, dass Erlang vorhanden ist.

Ich weiß nicht, was die Konvention, aber imho, wie Erlang-like wie möglich. Machen Sie Heap-Objekte unveränderlich und eine Art von Message-Passing-Protokoll eingerichtet zwischen Threads zu kommunizieren. Vermeiden Schleusen. Stellen Sie sicher, dass das Message-Passing ist Ausnahme sicher. Halten Sie so viele Stateful Sachen auf dem Stapel.

Wie andere besprochen haben, Concurrency (und Thread-Sicherheit insbesondere) ist ein architektonisches Problem, das wirkt sich, wie Sie entwerfen Ihr System und Ihre Anwendung.

Aber ich mag Ihre Frage zu Spannungen zwischen ausnahme Sicherheit und Thread-Sicherheit nehmen.

Auf der Ebene der Klassen Thread-Sicherheit erfordert Änderungen an der Schnittstelle. Genau wie Ausnahme-Sicherheit tut. Zum Beispiel ist es üblich, für die Klassen Verweise auf interne Variablen zurückzukehren, sagen:

class Foo {
public:
  void set_value(std::string const & s);

  std::string const & value() const;
};

Wenn Foo von mehreren Threads gemeinsam genutzt wird, erwarten Sie Schwierigkeiten. Natürlich könnten Sie einen Mutex oder andere Sperre für den Zugriff auf Foo setzen. Aber bald genug, alle C ++ Programmierer möchte Foo einzuwickeln in eine „ThreadSafeFoo“. Meine Behauptung ist, dass die Schnittstelle für Foo sollte geändert werden:

class Foo {
public:
  void set_value(std::string const & s);

  std::string value() const;
};

Ja, ist es teurer, aber es kann innerhalb Foo Thread-sicher mit Schlössern gemacht werden. IMNSHO dies schafft eine gewisse Spannung zwischen gewinde Sicherheit und ausnahme Sicherheit. Oder zumindest, müssen Sie mehr Analysen durchführen, da jede Klasse als gemeinsame Ressource verwendet wird, muss unter den beiden Leuchten geprüft werden.

Ein klassisches Beispiel (kann mich nicht erinnern, wo ich es zum ersten Mal sah) in der Standardbibliothek.

Hier ist, wie man etwas aus einer Warteschlange Pop:

T t;
t = q.front(); // may throw
q.pop();

Diese Schnittstelle ist etwas stumpf im Vergleich zu:

T t = q.pop();

Aber geschieht, weil die T Kopie Zuordnung werfen. Wenn die Kopie wirft nach dem Pop geschieht, wird dieses Element aus der Warteschlange verloren und nie zurückgewonnen werden kann. Da aber die Kopie geschieht, bevor das Element aufgetaucht ist, können Sie beliebige Handhabung setzen um die Kopie von vorne () in try / catch-Blöcke.

Der Nachteil ist, dass Sie nicht eine Warteschlange implementieren können, die Gewinde mit std :: Warteschlange Schnittstelle sicher ist beteiligt, weil die beiden Schritte. Was für die Ausnahme Sicherheit gut ist (Aussondern Schritte, die werfen), schlecht ist jetzt Multithreading.

Ihr Haupt Retter in Ausnahme Sicherheit ist, dass Zeigeroperationen sind kein Wurf. In ähnlicher Weise können Zeigeroperationen auf den meisten Plattformen Atom gemacht werden, so dass sie oft dein Retter in multithreaded Code sein. Sie können Ihren Kuchen haben und ihn auch essen, aber es ist wirklich schwer.

Es gibt zwei Fragen, die ich bemerkt:

  • in g ++ auf Linux, die Tötung eines Fadens (pthread_cancel) durch Auslösen einer "unbekannten" Ausnahme erreicht. Auf der einen Seite, mit dem Sie gut reinigen, wenn der Faden getötet wird. Auf der anderen Seite, wenn Sie diese Ausnahme zu fangen und sie erneut auslösen es nicht, Ihr Code endet mit Abbruch (). Deshalb, wenn Sie oder eine der Bibliotheken, die Sie töten Threads verwenden, können Sie nicht haben

    catch (...)

ohne

throw;

in Ihrem Gewinde Code. Hier ist dieses Verhalten im Web eine Referenz:

  • Manchmal müssen Sie Ausnahme zwischen Threads übertragen. Dies ist keine einfache Sache zu tun -. Wir am Ende somehack tun, wenn die richtige Lösung die Art der Rangierung ist / demarshalling Sie zwischen Prozessen verwenden würde

Ich empfehle nicht jede Ausnahme im Stich gelassen bleiben abgefangene. Wickeln Sie Ihre Top-Level-Thread-Funktionen in Catch-all-Handler, die anmutige können (oder zumindest verbosely) das Programm heruntergefahren wird.

Ich denke, das Wichtigste ist, dass abgefangene Ausnahmen von anderen Threads zu erinnern, zeigen nicht an den Benutzer oder an dem Haupt-Thread geworfen. So haben Sie den gesamten Code verziehen, die mit try / catch-Blöcke auf Threads anders als die Haupt-Thread ausgeführt werden soll.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top