Implementing the Singleton pattern in C++ Klaus Sembritzki Introduction Definition Where to use it Log class Implementing the Singleton pattern in C++ Static members Static instance Static instance pointer Pure Singleton implementations Static instance pointer Meyers Singleton Phoenix Singleton Multithreaded access Klaus Sembritzki FAU Erlangen Nürnberg 7. Juni 2010 Coherent cache Non-coherent cache Compilerdependent solutions Resources 1 / 39 Table of Contents Implementing the Singleton pattern in C++ Klaus Sembritzki Introduction Definition Where to use it Log class Static members Static instance Static instance pointer Pure Singleton implementations Static instance pointer Meyers Singleton Phoenix Singleton Multithreaded access Coherent cache Non-coherent cache Compilerdependent solutions Resources 1 Introduction Definition Where to use it 2 Log class Static members Static instance Static instance pointer 3 Pure Singleton implementations Static instance pointer Meyers Singleton Phoenix Singleton 4 Multithreaded access Coherent cache Non-coherent cache Compiler-dependent solutions 5 Resources 2 / 39 What is a Singleton Implementing the Singleton pattern in C++ Klaus Sembritzki Introduction Definition Where to use it Log class Static members Static instance Static instance pointer Pure Singleton implementations Static instance pointer Meyers Singleton Phoenix Singleton Multithreaded access Coherent cache Non-coherent cache Compilerdependent solutions Definition A Singleton is a class/object that has at most one instance, that one instance can be accessed globally. More requirements Singleton creates itself when used for the first time. Singleton destroys itself some time. ⇒ A little bit more than a global variable Resources 3 / 39 Warning Implementing the Singleton pattern in C++ Klaus Sembritzki Introduction Definition Where to use it Log class Static members Static instance Static instance pointer Pure Singleton implementations Static instance pointer Meyers Singleton Phoenix Singleton Multithreaded access Coherent cache Non-coherent cache Compilerdependent solutions Singletons considered harmful (compare to global variables) Refactoring required when more than one instance needed Methods should only work on input arguments Accesses scattered all over the application Use Singleton if You will never need more than one instance Passing a parameter would be a pain Accesses will be scattered anyway Resources 4 / 39 Usage examples Implementing the Singleton pattern in C++ Provide access to hardware ressources as they only exists once Klaus Sembritzki Keyboard Introduction Definition Where to use it Log class Static members Static instance Static instance pointer Pure Singleton implementations Static instance pointer Meyers Singleton Phoenix Singleton Display System clock Other examples Print manager Database access Log file Multithreaded access Coherent cache Non-coherent cache Compilerdependent solutions Anti-pattern ? Singletons are used very frequently Resources 5 / 39 Table of Contents Implementing the Singleton pattern in C++ Klaus Sembritzki Introduction Definition Where to use it Log class Static members Static instance Static instance pointer Pure Singleton implementations Static instance pointer Meyers Singleton Phoenix Singleton Multithreaded access Coherent cache Non-coherent cache Compilerdependent solutions Resources 1 Introduction Definition Where to use it 2 Log class Static members Static instance Static instance pointer 3 Pure Singleton implementations Static instance pointer Meyers Singleton Phoenix Singleton 4 Multithreaded access Coherent cache Non-coherent cache Compiler-dependent solutions 5 Resources 6 / 39 Static members Implementing the Singleton pattern in C++ Klaus Sembritzki 1 2 3 Introduction Definition Where to use it Log class Static members Static instance Static instance pointer Pure Singleton implementations Static instance pointer Meyers Singleton Phoenix Singleton Multithreaded access Coherent cache Non-coherent cache Compilerdependent solutions Resources 4 5 6 7 8 9 10 11 12 // Header f i l e L o g F i l e . h class LogFile { public : s t a t i c v o i d w r i t e ( c o n s t s t d : : s t r i n g &message ) { f i l e << message << s t d : : e n d l ; } s t a t i c void w r i t e S e p a r a t o r L i n e () { f i l e << ”−−−−−” << s t d : : e n d l ; } private : static std : : ofstream f i l e ; }; 13 14 15 // S o u r c e f i l e L o g F i l e . cpp s t d : : o f s t r e a m L o g F i l e : : f i l e ( ” Log1 . t x t ” ) ; 16 17 18 // S o u r c e f i l e Main . cpp LogFile : : w r i t e ( ” a l l your base ” ) ; 7 / 39 Static members (2) Implementing the Singleton pattern in C++ Klaus Sembritzki Problems Time of initialization unclear Introduction Definition Where to use it Log class Time of destruction unclear Static members Static instance Static instance pointer Hard to check for errors (did file-open succeed?) Pure Singleton implementations Static instance pointer Meyers Singleton Phoenix Singleton Multithreaded access 1 2 3 s t d : : o f s t r e a m L o g F i l e : : f i l e ( ” Log1 . t x t ” ) ; // I n i t i a l i z a t i o n o f s o m e O b j e c t d e p e n d s on f i l e SomeClass L o g F i l e : : someObject ( L o g F i l e : : f i l e ) ; Coherent cache Non-coherent cache Compilerdependent solutions Resources 8 / 39 Static instance Implementing the Singleton pattern in C++ Klaus Sembritzki Introduction Definition Where to use it Log class Static members Static instance Static instance pointer Pure Singleton implementations Static instance pointer Meyers Singleton Phoenix Singleton Multithreaded access Coherent cache Non-coherent cache Compilerdependent solutions 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 // Header f i l e Log . h c l a s s Log { public : s t a t i c Log& i n s t a n c e ( ) { return inst ance ; } v o i d w r i t e ( c o n s t s t d : : s t r i n g &message ) { . . . } private : Log ( ) : f i l e ( ” Log3 . t x t ” ) {} s t a t i c Log i n s t a n c e ; std : : ofstream f i l e ; }; // S o u r c e f i l e Log . cpp Log Log : : i n s t a n c e ; // S o u r c e f i l e Main . cpp Log : : i n s t a n c e ( ) . w r i t e ( ”msg” ) ; Resources 9 / 39 Static instance (2) Implementing the Singleton pattern in C++ Klaus Sembritzki Introduction Definition Where to use it Log class Static members Static instance Static instance pointer Problems Time of initialization unclear Time of destruction unclear Pure Singleton implementations Static instance pointer Meyers Singleton Phoenix Singleton Multithreaded access Consequence of unclear initialization time Log constructor accesses another Singleton object ⇒ might use uninitialized data Coherent cache Non-coherent cache Compilerdependent solutions Resources 10 / 39 Static instance pointer Implementing the Singleton pattern in C++ Klaus Sembritzki 1 2 3 Introduction Definition Where to use it Log class Static members Static instance Static instance pointer Pure Singleton implementations Static instance pointer Meyers Singleton Phoenix Singleton Multithreaded access Coherent cache Non-coherent cache Compilerdependent solutions Resources 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 // Header f i l e Log . h c l a s s Log { public : s t a t i c Log& i n s t a n c e ( ) { i f ( i n s t a n c e == 0 ) i n s t a n c e = new Log ( ) ; return ∗ instance ; } v o i d w r i t e ( c o n s t s t d : : s t r i n g &message ) { . . . } private : Log ( ) : f i l e ( ” Log4 . t x t ” ) {} s t a t i c Log ∗ i n s t a n c e ; std : : ofstream f i l e ; }; // S o u r c e f i l e Log . cpp Log ∗ Log : : i n s t a n c e = 0 ; // S o u r c e f i l e Main . cpp Log : : i n s t a n c e ( ) . w r i t e ( ” h e l l o ” ) ; 11 / 39 Table of Contents Implementing the Singleton pattern in C++ Klaus Sembritzki Introduction Definition Where to use it Log class Static members Static instance Static instance pointer Pure Singleton implementations Static instance pointer Meyers Singleton Phoenix Singleton Multithreaded access Coherent cache Non-coherent cache Compilerdependent solutions Resources 1 Introduction Definition Where to use it 2 Log class Static members Static instance Static instance pointer 3 Pure Singleton implementations Static instance pointer Meyers Singleton Phoenix Singleton 4 Multithreaded access Coherent cache Non-coherent cache Compiler-dependent solutions 5 Resources 12 / 39 Improvements Implementing the Singleton pattern in C++ Klaus Sembritzki Introduction Definition Where to use it Log class Static members Static instance Static instance pointer Pure Singleton implementations Static instance pointer Meyers Singleton Phoenix Singleton Multithreaded access Enforce uniqueness, prevent clients from calling the Singleton’s default constructor using the copy constructor using the assignment operator (only one Singleton object can exist) Automatically destroy on program exit Disallow destruction Coherent cache Non-coherent cache Compilerdependent solutions Resources 13 / 39 Static instance pointer Implementing the Singleton pattern in C++ Klaus Sembritzki Introduction Definition Where to use it Log class Static members Static instance Static instance pointer Pure Singleton implementations Static instance pointer Meyers Singleton Phoenix Singleton Multithreaded access Coherent cache Non-coherent cache Compilerdependent solutions 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 // H e a d e r f i l e S i n g l e t o n . h class Singleton { public : s t a t i c S i n g l e t o n& i n s t a n c e ( ) { i f ( i n s t a n c e == 0 ) { i n s t a n c e = new S i n g l e t o n ( ) ; s t d : : a t e x i t (& d e l e t e S i n g l e t o n ) ; } return ∗ instance ; } private : S i n g l e t o n ( ) {} S i n g l e t o n ( c o n s t S i n g l e t o n &) ; S i n g l e t o n &o p e r a t o r =( c o n s t S i n g l e t o n &) ; ˜ S i n g l e t o n ( ) {} s t a t i c void d e l e t e S i n g l e t o n () { delete instance ; } static Singleton ∗instance ; }; // S o u r c e f i l e S i n g l e t o n . cpp Singleton∗ Singleton : : instance = 0; Resources 14 / 39 Meyers Singleton Implementing the Singleton pattern in C++ Klaus Sembritzki 1 Introduction Definition Where to use it Log class Static members Static instance Static instance pointer Pure Singleton implementations Static instance pointer Meyers Singleton Phoenix Singleton Multithreaded access Coherent cache Non-coherent cache Compilerdependent solutions 2 3 4 5 6 7 8 9 10 11 12 13 // Header f i l e S i n g l e t o n . h class Singleton { public : s t a t i c S i n g l e t o n& i n s t a n c e ( ) { static Singleton instance ; return instance ; } private : S i n g l e t o n ( ) {} S i n g l e t o n ( c o n s t S i n g l e t o n &) ; S i n g l e t o n &o p e r a t o r =( c o n s t S i n g l e t o n &) ; ˜ S i n g l e t o n ( ) {} }; Resources 15 / 39 Atexit contradiction Implementing the Singleton pattern in C++ Klaus Sembritzki Introduction Definition Where to use it Log class Static members Static instance Static instance pointer Pure Singleton implementations Static instance pointer Meyers Singleton Phoenix Singleton Multithreaded access Coherent cache Non-coherent cache Compilerdependent solutions 1 v o i d Log : : d e s t r o y ( ) {} 2 3 4 5 6 void Display : : destroy () { Log : : i n s t a n c e ( ) a t e x i t (&Log : : d e s t r o y ) ; } 7 8 9 10 11 v o i d main ( ) { Display : : instance () a t e x i t (& D i s p l a y : : d e s t r o y ) ; } Contradiction According to standard: last in, first called Not possiple here ⇒ Some compilers crash, do not call bar, ... (g++ 4.3.4 worked) Resources 16 / 39 Dead reference problem Implementing the Singleton pattern in C++ Klaus Sembritzki atexit and static destructors work in LIFO order. Introduction Definition Where to use it Program with two classes, Display (access to rendering device) and the Log class Log class Static members Static instance Static instance pointer 1 Pure Singleton implementations 3 Static instance pointer Meyers Singleton Phoenix Singleton 2 4 5 6 Display : : instance () a t e x i t (& D i s p l a y : : d e s t r o y ) ; Log : : i n s t a n c e ( ) a t e x i t (&Log : : d e s t r o y ) ; ˜ Log ( ) ˜ Display () Multithreaded access Coherent cache Non-coherent cache Compilerdependent solutions ˜Display() writes to log ⇒ undefined behaviour Resources 17 / 39 Dead reference problem, throw exception Detect the dead reference and throw an exception Implementing the Singleton pattern in C++ Klaus Sembritzki 1 2 Introduction Definition Where to use it Log class Static members Static instance Static instance pointer Pure Singleton implementations Static instance pointer Meyers Singleton Phoenix Singleton Multithreaded access Coherent cache Non-coherent cache Compilerdependent solutions Resources 3 4 5 6 7 8 9 10 11 12 13 // S i n g l e t o n . h class Singleton { public : s t a t i c S i n g l e t o n& i n s t a n c e ( ) { static Singleton inst ; i f ( destroyed ) throw s t d : : r u n t i m e e r r o r ( ”Dead r e f e r e n c e detected ”) ; return i n s t ; } private : ˜ Singleton () { destroyed = true ; } s t a t i c bool d e s t r o y e d ; }; 14 15 16 // S i n g l e t o n . cpp bool S i n g l e t o n : : d e s t r o y e d = false ; 18 / 39 Dead reference problem, Phoenix Singleton Implementing the Singleton pattern in C++ Klaus Sembritzki Introduction Definition Where to use it Log class Static members Static instance Static instance pointer Pure Singleton implementations Static instance pointer Meyers Singleton Phoenix Singleton Multithreaded access Coherent cache Non-coherent cache Compilerdependent solutions 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 // S i n g l e t o n . h class Singleton { public : s t a t i c S i n g l e t o n& i n s t a n c e ( ) { static Singleton inst ; i n s t a n c e = &i n s t ; i f ( destroyed ) { new ( i n s t a n c e ) S i n g l e t o n ( ) ; std : : a t e x i t ( destroySingleton ) ; destroyed = false ; } return inst ; } private : ˜ Singleton () { destroyed = true ; } s t a t i c v o i d d e s t r o y S i n g l e t o n ( ) { i n s t a n c e −>˜S i n g l e t o n ( ) ; } s t a t i c bool destroyed ; static Singleton ∗instance ; }; // S i n g l e t o n . cpp Singleton ∗Singleton : : instance = 0; bool Singleton : : destroyed = f a l s e ; Resources 19 / 39 Dead reference problem, Phoenix Singleton (2) Implementing the Singleton pattern in C++ Klaus Sembritzki Introduction Definition Where to use it Log class Static members Static instance Static instance pointer Pure Singleton implementations Static instance pointer Meyers Singleton Phoenix Singleton Multithreaded access Remember the Log example Constructor clears whole log file. ⇒ Repeated Phoenix constructor calls will delete logging information. Possible solutions Priority based atexit function (non-standard) Create Singletons manually at start of main() (hack) Destroy manually at the end of main() (hack) Coherent cache Non-coherent cache Compilerdependent solutions Resources 20 / 39 Table of Contents Implementing the Singleton pattern in C++ Klaus Sembritzki Introduction Definition Where to use it Log class Static members Static instance Static instance pointer Pure Singleton implementations Static instance pointer Meyers Singleton Phoenix Singleton Multithreaded access Coherent cache Non-coherent cache Compilerdependent solutions Resources 1 Introduction Definition Where to use it 2 Log class Static members Static instance Static instance pointer 3 Pure Singleton implementations Static instance pointer Meyers Singleton Phoenix Singleton 4 Multithreaded access Coherent cache Non-coherent cache Compiler-dependent solutions 5 Resources 21 / 39 The volatile keyword Implementing the Singleton pattern in C++ Klaus Sembritzki Introduction Definition Where to use it Log class Static members Static instance Static instance pointer Pure Singleton implementations Static instance pointer Meyers Singleton Phoenix Singleton Properties of “volatile” variables Access directly translated into assembler “mov” instruction. ⇒ not kept in a register. Accesses are not reordered. But: Accesses to non-volatile variables can still be reordered with accesses to volatile variables. Multithreaded access Coherent cache Non-coherent cache Compilerdependent solutions Resources 22 / 39 Cache coherence Implementing the Singleton pattern in C++ Klaus Sembritzki Introduction Definition Where to use it cpu 0 cpu 1 Log class Static members Static instance Static instance pointer cache 0 coherent? cache 1 Pure Singleton implementations Static instance pointer Meyers Singleton Phoenix Singleton Multithreaded access ram Coherent cache Non-coherent cache Compilerdependent solutions Resources 23 / 39 Cache coherence (2) Implementing the Singleton pattern in C++ Klaus Sembritzki Introduction Definition Where to use it Log class Static members Static instance Static instance pointer Cache coherence If hardware enforces cache coherence local caches of all processores are automatically synchronized. Pure Singleton implementations Static instance pointer Meyers Singleton Phoenix Singleton ⇒ Programmer does not need to care about the existance of caches at all (except for performance reasons). Multithreaded access Coherent cache Non-coherent cache Compilerdependent solutions Resources 24 / 39 Cache coherence (3) Implementing the Singleton pattern in C++ Klaus Sembritzki Introduction Definition Where to use it Log class Static members Static instance Static instance pointer Let us first assume that our hardware always provides a coherent cache (which is the case on x86 hardware) Pure Singleton implementations Static instance pointer Meyers Singleton Phoenix Singleton Note that we still need to care about the existence of registers. Multithreaded access Coherent cache Non-coherent cache Compilerdependent solutions Resources 25 / 39 Simple implementation Implementing the Singleton pattern in C++ 1 Klaus Sembritzki 2 Introduction Definition Where to use it Log class Static members Static instance Static instance pointer Pure Singleton implementations Static instance pointer Meyers Singleton Phoenix Singleton Multithreaded access Coherent cache Non-coherent cache Compilerdependent solutions Resources 3 4 5 6 7 8 9 10 11 12 13 14 class Singleton { public : s t a t i c S i n g l e t o n& i n s t a n c e ( ) { // l o c k ’ s c o n s t r u c t o r e n t e r s c r i t i c a l s e c t i o n Lock l o c k ; i f ( i n s t a n c e == 0 ) { i n s t a n c e = new S i n g l e t o n ( ) ; } return ∗ instance ; // l o c k ’ s d e s t r u c t o r l e a v e s c r i t i c a l s e c t i o n } private : static Singleton ∗ volatile instance ; }; The code works. Note the position of the volatile keyword (compare to const). 26 / 39 Double-checked locking Implementing the Singleton pattern in C++ Klaus Sembritzki Introduction Definition Where to use it Log class Static members Static instance Static instance pointer Pure Singleton implementations Static instance pointer Meyers Singleton Phoenix Singleton Multithreaded access Coherent cache Non-coherent cache Compilerdependent solutions Resources 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class Singleton { public : s t a t i c S i n g l e t o n& i n s t a n c e ( ) { i f ( i n s t a n c e == 0 ) { Lock l o c k ; // v o l a t i l e n e s s f o r c e s r e −r e a d i f ( i n s t a n c e == 0 ) { // p r o b l e m a t i c , s e e n e x t s l i d e S i n g l e t o n ∗ v o l a t i l e tmp = new S i n g l e t o n ( ) ; i n s t a n c e = tmp ; } } return ∗ instance ; } private : Singleton () { x = 7; } static Singleton ∗ volatile instance ; int x ; }; 27 / 39 Double-checked locking, inlined constructor Implementing the Singleton pattern in C++ Klaus Sembritzki Introduction Definition Where to use it Log class Static members Static instance Static instance pointer 1 2 3 4 5 6 7 8 Pure Singleton implementations Static instance pointer Meyers Singleton Phoenix Singleton Multithreaded access Coherent cache Non-coherent cache Compilerdependent solutions Resources 9 10 11 12 13 14 15 16 17 class Singleton { public : s t a t i c S i n g l e t o n& i n s t a n c e ( ) { i f ( i n s t a n c e == 0 ) { Lock l o c k ; i f ( i n s t a n c e == 0 ) { // a c c e s s t o non− v o l a t i l e members may be r e o r d e r e d . S i n g l e t o n ∗ v o l a t i l e tmp = s t a t i c c a s t <S i n g l e t o n ∗>( o p e r a t o r new ( s i z e o f ( S i n g l e t o n ) ) ) ; tmp−>x = 7 ; i n s t a n c e = tmp ; } } return ∗ instance ; } private : static Singleton ∗ volatile instance ; int x ; }; 28 / 39 Double-checked locking, volatile idea Implementing the Singleton pattern in C++ Klaus Sembritzki Introduction Definition Where to use it Log class Idea Make pointer contents volatile Static members Static instance Static instance pointer Pure Singleton implementations Static instance pointer Meyers Singleton Phoenix Singleton Multithreaded access Problem Like const-objects that only become const after their constructors have run to completion, volatile objects only become volatile after their constructors finished. Coherent cache Non-coherent cache Compilerdependent solutions Resources 29 / 39 Double-checked locking, volatile pointer Implementing the Singleton pattern in C++ Klaus Sembritzki Introduction Definition Where to use it Log class Static members Static instance Static instance pointer Pure Singleton implementations Static instance pointer Meyers Singleton Phoenix Singleton Multithreaded access Coherent cache Non-coherent cache Compilerdependent solutions Resources 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class Singleton { public : s t a t i c v o l a t i l e S i n g l e t o n& i n s t a n c e ( ) { i f ( i n s t a n c e == 0 ) { Lock l o c k ; i f ( i n s t a n c e == 0 ) { v o l a t i l e S i n g l e t o n ∗ v o l a t i l e tmp = new volatile Singleton () ; i n s t a n c e = tmp ; } } return ∗ instance ; } private : Singleton () { x = 7; } // c o n t e n t s o n l y v o l a t i l e b e c a u s e tmp c o u l d o t h e r w i s e n o t be c a s t e d static volatile Singleton ∗ volatile instance ; int x ; }; 30 / 39 Double-checked locking, cast to volatile Implementing the Singleton pattern in C++ Klaus Sembritzki Introduction Definition Where to use it Log class Static members Static instance Static instance pointer Pure Singleton implementations Static instance pointer Meyers Singleton Phoenix Singleton Multithreaded access Coherent cache Non-coherent cache Compilerdependent solutions Resources 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class Singleton { public : s t a t i c S i n g l e t o n& i n s t a n c e ( ) { i f ( i n s t a n c e == 0 ) { Lock l o c k ; i f ( i n s t a n c e == 0 ) { S i n g l e t o n ∗ v o l a t i l e tmp = new S i n g l e t o n ( ) ; i n s t a n c e = tmp ; } } return ∗ instance ; } private : S i n g l e t o n ( ) { s t a t i c c a s t <v o l a t i l e i n t &>(x ) = 7 ; } static Singleton ∗ volatile instance ; int x ; }; This solution works. 31 / 39 Double-checked locking, barrier Implementing the Singleton pattern in C++ 1 Klaus Sembritzki 2 3 Introduction Definition Where to use it Log class Static members Static instance Static instance pointer Pure Singleton implementations Static instance pointer Meyers Singleton Phoenix Singleton Multithreaded access Coherent cache Non-coherent cache Compilerdependent solutions Resources 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class Singleton { public : s t a t i c S i n g l e t o n& i n s t a n c e ( ) { i f ( i n s t a n c e == 0 ) { Lock l o c k ; i f ( i n s t a n c e == 0 ) { S i n g l e t o n ∗tmp = new S i n g l e t o n ( ) ; // ( . . . ) memory b a r r i e r i n s t a n c e = tmp ; } } return ∗ instance ; } private : Singleton () { x = 7; } static Singleton ∗ volatile instance ; int x ; }; This solution works. 32 / 39 Non-coherent caches and volatile Implementing the Singleton pattern in C++ Klaus Sembritzki Introduction Definition Where to use it Log class Static members Static instance Static instance pointer Reminder Volatileness simply produces ordered “mov” assembler instructions, those can result in writing to the cache or the main memory. Pure Singleton implementations Static instance pointer Meyers Singleton Phoenix Singleton ⇒ Volatileness is useless if the caches are not coherent. Multithreaded access Coherent cache Non-coherent cache Compilerdependent solutions Resources 33 / 39 Simple implementation, barrier Implementing the Singleton pattern in C++ Klaus Sembritzki 1 2 Introduction Definition Where to use it Log class Static members Static instance Static instance pointer Pure Singleton implementations Static instance pointer Meyers Singleton Phoenix Singleton Multithreaded access Coherent cache Non-coherent cache Compilerdependent solutions 3 4 5 6 7 8 9 10 11 12 13 s t a t i c S i n g l e t o n& i n s t a n c e ( ) { Lock l o c k ; // ( . . . ) r e a d i n s t a n c e and members from memory // why r e a d t h e members // − memory m i gh t h a v e been m a l l o c e d by // a n o t h e r o b j e c t and f r e e d t h e n // − cache l i n e s i f ( i n s t a n c e == 0 ) { S i n g l e t o n ∗ i n s t a n c e = new S i n g l e t o n ( ) ; // ( . . . ) w r i t e i n s t a n c e and i t s members t o main memory } return ∗ inst ance ; } This solution works. Resources 34 / 39 Double-checked locking, barrier Implementing the Singleton pattern in C++ Klaus Sembritzki 1 2 Introduction Definition Where to use it Log class Static members Static instance Static instance pointer Pure Singleton implementations Static instance pointer Meyers Singleton Phoenix Singleton Multithreaded access Coherent cache Non-coherent cache Compilerdependent solutions 3 4 5 6 7 8 9 10 11 12 13 14 s t a t i c S i n g l e t o n& i n s t a n c e ( ) { // ( . . . ) r e a d i n s t a n c e and members from memory i f ( i n s t a n c e == 0 ) { Lock l o c k ; // ( . . . ) r e a d i n s t a n c e and members from memory i f ( i n s t a n c e == 0 ) { S i n g l e t o n ∗tmp = new S i n g l e t o n ( ) ; // ( . . . ) w r i t e members o f tmp t o main memory i n s t a n c e = tmp ; // ( . . . ) w r i t e i n s t a n c e t o main memory } } return ∗ inst ance ; } This solution works. Resources 35 / 39 Compiler-dependent solutions Implementing the Singleton pattern in C++ Klaus Sembritzki Introduction Definition Where to use it Log class Static members Static instance Static instance pointer gcc supports thread-safe static local variables not covered by the standard. ⇒ optimized double-checked Meyers Singleton possible. volatile is not thread-safe Pure Singleton implementations Static instance pointer Meyers Singleton Phoenix Singleton Multithreaded access Coherent cache Non-coherent cache Compilerdependent solutions The Visual Studio compiler does not support thread-safe static local variables. Volatile is implemented in a thread safe fashion not covered by the standard. Resources 36 / 39 Recommendation Implementing the Singleton pattern in C++ Klaus Sembritzki Introduction Definition Where to use it Log class Static members Static instance Static instance pointer Pure Singleton implementations Static instance pointer Meyers Singleton Phoenix Singleton Use fencing (= barriers) with boost, switch to C++0x library when available. Multithreaded Singleton Implementations with boost are can be found online Multithreaded access Coherent cache Non-coherent cache Compilerdependent solutions Resources 37 / 39 Table of Contents Implementing the Singleton pattern in C++ Klaus Sembritzki Introduction Definition Where to use it Log class Static members Static instance Static instance pointer Pure Singleton implementations Static instance pointer Meyers Singleton Phoenix Singleton Multithreaded access Coherent cache Non-coherent cache Compilerdependent solutions Resources 1 Introduction Definition Where to use it 2 Log class Static members Static instance Static instance pointer 3 Pure Singleton implementations Static instance pointer Meyers Singleton Phoenix Singleton 4 Multithreaded access Coherent cache Non-coherent cache Compiler-dependent solutions 5 Resources 38 / 39 Resources Implementing the Singleton pattern in C++ Klaus Sembritzki Introduction Definition Where to use it Modern C++ Design, Andrei Alexandrescu ISBN 0-201-70431-5 Log class Static members Static instance Static instance pointer Pure Singleton implementations Static instance pointer Meyers Singleton Phoenix Singleton Multithreaded access Coherent cache Non-coherent cache Compilerdependent solutions http://www.codeproject.com/KB/threads/DoubleCheckedLocking.as http://blogs.msdn.com/b/kangsu/archive/2007/07/16/volatileacquire-release-memory-fences-and-vc2005.aspx http://software.intel.com/en-us/blogs/2007/11/30/volatilealmost-useless-for-multi-threaded-programming/ http://www.cs.umd.edu/ pugh/java/memoryModel/DoubleCheckedLocking.html Resources 39 / 39
© Copyright 2024