2014-09-11 5 views
6

std::shared_ptr ist garantiert fadensicher. Ich weiß nicht, welchen Mechanismus die typischen Implementierungen verwenden, um dies sicherzustellen, aber sicherlich muss es einige Gemeinkosten haben. Und dieser Overhead wäre auch dann vorhanden, wenn Ihre Anwendung single-threaded ist.Wie hoch ist der Overhead von shared_ptr threadsicher?

Ist das oben der Fall? Und wenn ja, verstößt das gegen den Grundsatz "Sie zahlen nicht für das, was Sie nicht nutzen", wenn Sie die Sicherheitsgarantien nicht nutzen?

+0

Aus dem Speicher verfügt die Loki-Bibliothek über intelligente Zeiger mit einer Thread-Sicherheitsrichtlinie, die dieses Problem beheben. –

+0

FYI, http://Stackoverflow.com/questions/15129263/is-there-a-non-atomic-equivalent-of-stdshared-ptr-and-why-ist-there-one-in –

Antwort

4

Zumindest im Boost-Code auf i386 wurde boost::shared_ptr mit einer atomaren CAS-Operation implementiert. Dies bedeutet, dass es, während es etwas Overhead hat, ziemlich niedrig ist. Ich würde erwarten, dass jede Implementierung von std::shared_ptr ähnlich ist.

In engen Schleifen in hoher Leistung numerischen Code fand ich einige Beschleunigungen durch den Wechsel zu rohen Zeigern und sehr vorsichtig sein. Aber für normalen Code - ich würde mir keine Sorgen machen.

+1

Ich bin mir ziemlich sicher Alle wichtigen Implementierungen nutzen Atomics. Ich weiß, Microsoft tut, zum einen. –

+0

@VioletGiraffe: Nicht alle Hardware-Plattformen unterstützen blockierungsfreie Atomzähler. Ältere ARMs zum Beispiel nicht. –

+2

Atomare Operationen sind ziemlich teuer. Das letzte Mal, das ich gemessen habe, glaube ich, dass es typischerweise etwa 20 ns pro atomarer Operation auf einer typischen Intel-CPU war. In der Größenordnung von 100-mal langsamer als eine normale Operation. –

8

Wenn wir überprüfen cppreference Seite für std::shared_ptr sie die folgenden in der Implementierung Staatsbons Abschnitt:

Gewinde Sicherheitsanforderungen gerecht zu werden, werden die Referenzzähler typischerweise erhöht und erniedrigt std::atomic::fetch_add mit std::memory_order_relaxed verwenden.

Es ist interessant, eine tatsächliche Implementierung zu beachten, zum Beispiel des libstdc++ Implementierung Dokument here sagt:

Für die Version von shared_ptr in libstdC++ Compiler und Bibliothek festgelegt sind, die Dinge viel einfacher macht : Wir haben eine atomare CAS oder wir nicht, siehe Lock-Politik unten für Details.

Die Auswahl von Schloss Politik Abschnitt sagt (Hervorhebung von mir):

Es gibt eine einzige _Sp_counted_base-Klasse, die eine Vorlage parametrisierte auf dem ENUM ist __gnu_cxx :: _ Lock_policy. Die gesamte Familie der Klassen ist in der Sperrrichtlinie bis zu __shared_ptr, __weak_ptr und __enable_shared_from_this parametrisiert. Die tatsächliche Klasse std :: shared_ptr erbt von __shared_ptr mit der Sperrrichtlinie Parameter automatisch basierend auf dem Thread-Modell und Plattform, für die libstdC++ konfiguriert ist, ausgewählt, so dass die beste verfügbare Vorlage Spezialisierung wird verwendet werden. Dieser Entwurf ist notwendig, weil es nicht konform sein würde, dass shared_ptr einen zusätzlichen Parameter der Vorlage hätte, selbst wenn er einen Standardwert hätte. Die verfügbaren Richtlinien sind:

[...]

3._S_Single

Diese Politik verwendet eine nichtablaufinvarianten add_ref_lock() ohne Verriegelung. Es wird verwendet, wenn libstdC++ ohne --enable-threads erstellt wird.

und sagt weiter (Hervorhebung von mir):

Für alle drei Strategien, Referenzzähler und -dekremente werden über die Funktionen in ext/atomicity.h getan, die, wenn das Programm erkennen ist Multi-Threaded. Wenn im Programm nur ein Ausführungs-Thread vorhanden ist, werden weniger teure nicht-atomare Operationen verwendet.

Also zumindest in dieser Implementierung bezahlen Sie nicht für das, was Sie nicht verwenden.

+1

"memory_order_relaxed \t Entspannte Operation: Es gibt keine Synchronisation oder Reihenfolge Einschränkungen, nur Atomizität dieser Operation erforderlich ist." Das klingt * nicht * richtig! – curiousguy