2012-09-06 11 views
11

Ich habe viele Fragen gelesen, die thread-safe Double Checked Locking (für Singletons oder Lazy Init) berücksichtigen. In einigen Threads lautet die Antwort, dass das Muster vollständig unterbrochen ist, andere schlagen eine Lösung vor.C++ 11: Sicheres doppelt geprüftes Sperren für verzögerte Initialisierung. Möglich?

Meine Frage ist also: Gibt es eine Möglichkeit, ein vollständig threadsicheres doppelt überprüftes Sperrmuster in C++ zu schreiben? Wenn ja, wie sieht es aus?

Wir können C++ 11 annehmen, wenn das die Dinge einfacher macht. Soweit ich weiß, hat C++ 11 das Speichermodell verbessert, was zu den notwendigen Verbesserungen führen könnte.

Ich weiß, dass es in Java möglich ist, indem Sie die Double-Check-Variable flüchtig machen. Da C++ 11 große Teile des Speichermodells von demjenigen von Java ausgeliehen hat, denke ich, dass es möglich sein könnte, aber wie?

+5

Wenn Sie C++ 11 verwenden können, ignorieren Sie einfach das gesamte doppelt überprüfte Sperrgeschäft und verwenden Sie entweder statische lokale Variablen oder 'std :: call_once'. –

+0

Werden statische Locals träge initialisiert? Und über 'call_once': Wie stellt dies sicher, dass der Aufruf einmal nicht den nicht vollständig erstellten Verweis auf die Variable schreibt? – gexicide

+3

Ja, statische Einheimische werden auf thread-sichere Weise träge initialisiert. Und 'call_once' stellt sicher, dass das Thema nur einmal aufgerufen wird; und dass kein anderer Aufruf von 'call_once' zurückkommt, bevor derjenige, der die Funktion tatsächlich ausführt, zurückkehrt (Sie können hier mehr lesen http://en.cppreference.com/w/cpp/thread/call_once). Wie es funktioniert, hängt von der Implementierung ab. Diese zwei Dinge existieren im Grunde, so dass Sie sich nicht mehr mit dem Schreiben von Bugs doppelt geprüften Sperrimplementierungen beschäftigen möchten. –

Antwort

16

Verwenden Sie einfach eine statische lokale Variable für lazily initialisierten Singletons, etwa so:

MySingleton* GetInstance() { 
    static MySingleton instance; 
    return &instance; 
} 

Die (C++ 11) Standard garantiert schon, dass statische Variablen in einer Thread-Weise initialisiert werden, und es scheint wahrscheinlich, dass die Implementierung von diesem mindestens so robust und performant wie alles, was Sie selbst schreiben würden.

Wenn die Steuerung tritt in die Deklaration gleichzeitig während der Variablen entspricht die gleichzeitige Ausführung, werden initialisiert:

Die threadsafety der Initialisierung können in §6.7.4 des (C++ 11) Standard gefunden werden, warten Sie auf den Abschluss der Initialisierung.

+11

Das ist verrückt. Warum, oh warum, würdest du jemals einen Zeiger zurückgeben, wenn er ** niemals ** null sein kann? –

+1

@MatthieuM .: Vor allem, weil es die Leute weniger geneigt macht, das zugrunde liegende Objekt zu kopieren. Natürlich sollte ein gut entworfener Singleton ** keinen Kopierkonstruktor haben, aber trotzdem. Ich sehe wirklich nicht, wie die Rendite nach Referenz oder die Rückgabe nach Wert in diesem Fall von Bedeutung ist. Deshalb würde ich das kaum verrückt nennen. – Grizzly

+2

@Grizzly: Wenn ein Objekt nicht kopierbar sein soll, muss das Objekt dies erzwingen. Wenn ein Objekt eine Instanz haben sollte, auf die global zugegriffen werden kann, sollte es eine Funktion geben, die (wie Ihre) zu handhaben ist. Diese zwei Dinge sind getrennt, und es gibt keinen Grund, sie zu kombinieren. Deshalb ist das Singleton-Muster dumm. – GManNickG

3

Da Sie eine gültige DCLP C++ 11-Implementierung sehen wollten, hier ist eine.

Das Verhalten ist vollständig Thread-sicher und identisch mit GetInstance() in Grizzly's Antwort.

+0

In der Praxis möchten Sie Ihre 'mtx'- und' instance_p'-Variablen als globale Variablen außerhalb der Funktion deklarieren und nicht als Statik innerhalb der Funktion, da Sie ansonsten den Preis für die internen Prüfungen des Compilers über die Initialisierung von 'mtx' und' instance_p' bei _allem_ Aufruf, wobei der Punkt des doppelt-geprüften Sperrens vereitelt wird (da sich der Singleton auch leistungsmäßig einfach als statisch deklarieren lässt). – BeeOnRope

+0

@BeeOnRope Gültiger Punkt .. Ich habe diese Änderung vorgenommen. – LWimsey

+0

Vielleicht möchten Sie hinzufügen, dass Sie diesen Code grundsätzlich nie schreiben wollen. Grizzly's Antwort ist prägnanter und der Compiler könnte in Zukunft mehr Magie einfügen, um es schneller als diesen Code zu machen. – gexicide

Verwandte Themen