260 likes | 406 Views
Statics in Depth. Advanced C++ Programming Anton Kaiser, Summer Term 2012. In other words . Please Avoid Statics. Advanced C++ Programming Anton Kaiser, Summer Term 2012. Outline. Overview Global Objects Statics Initialization Problems Ordering Multithreading
E N D
Statics in Depth Advanced C++ Programming Anton Kaiser, Summer Term 2012
In otherwords... PleaseAvoidStatics Advanced C++ Programming Anton Kaiser, Summer Term 2012
Outline • Overview • Global Objects • Statics • Initialization • Problems • Ordering • Multithreading • Possible Solutions • AvoidingStatics • Singleton • Schwarz Counter • Spinlocks • Conclusions • Sources
Overview • Where do staticsreside? • Special part in thedatasegment • When do staticsexist? • Duringthewholelifetimeof a program • Whatiftheyhave not beeninitialized? • Staticprimitive variables areinitializedto NULL • Forobjects (likestrings) thestandardconstructor will becalled
Overview • Global objects • Accessiblefromeveryfileandfunctionoftheprogram • Typicalexamples: cin, cout, cerr, clog • //Class1.cpp • stringline; // global • intmain() {…} • //Class2.cpp • externstringline; • intlineSize() { • returnline.size(); • }
Overview • Staticobjects • Accessibleonlyfromfunctions in the same file, depending on thelocationtheyhavebeendefinedat • In thewholemodule, whendefined outside all functions • Locally in a blockwheredefined • //AccessControl.cpp • staticstringpassword = "coolPassword"; • booltestPasswordInput(string &pw) { • if (pw.compare (password) == 0) • returntrue; • elsereturnfalse; • } • //returnsthe time differencesincethe last call • longtimeDiff() { • statictime_tseconds = 0; //0 onlyassignedonce! • longoldSeconds = seconds; //save old time • time( &seconds); //getnew time • return (seconds - oldSeconds); //returndifference • }
Overview • Initialization • First phase: staticinitialization (atcompile time) • Second phase: dynamicinitialization • externintsomeOtherModulesFunc(); • namespaceStaticsAbound { • inlineintlocalFunc() { return 10 }; • struct Thing { • Thing() : i(someOtherModulesFunc()) {} • int i; • } thing; // dynamic • int i1 = 0; int i2; int i3 = 1; // static • int i4 = localFunc(); // static • int i5 = ::SomeOtherModulesFunc(); // dynamic • }
Outline • Overview • Global Objects • Statics • Initialization • Problems • Ordering • Multithreading • Possible Solutions • AvoidingStatics • Singleton • Schwarz Counter • Spinlocks • Conclusions • Sources
Problems:IntracompilationOrdering extern someObjecto2; // declaration someObject o1(o2); // undefined! someObject o1("o1"); // definition someObjecto2(o1); // thisisfine! intmain() { someObject o3("o3"); return 0; } • Objects areinitializedby order ofdefinition, not declaration!
Problems:IntercompilationOrdering // object.h classObject {…}; externObject o1; externObject o2; externObject o3; // object2.cpp • #include"object.h" • Object o2("o2"); // object3.cpp • #include"object.h" • Object o3("o3"); Recommendation • Don’t rely on global object initialization ordering • Do utilize global object initialization tracing mechanisms anyway // objects01.cpp • #include"object.h" • Object o0("o0"); • Object o1("o1"); • intmain() {...}
Problems: Multithreading (1) • Racecondition • Twothreadscouldbothseetheuninitializedresult int myFunction() { static int result = doCalculation(); return result; } int myFunction() { static bool finished = false; static int result; if (!finished) { finished = true; result = doCalculation(); } return result; } • Racecondition • Twothreadscouldreadfinishedsimultaniously,bothexecutedoCalculation()andwritetoresult
Problems: Multithreading (2) • Initialization • myClassmay not havebeeninitializedbeforethecalculation class MyClass {...}; int myFunction{...}; static MyClass myClass; return myClass.doCalculation(); } class MyClass {...}; int calculateResult() { static bool isConstructed = false; static MyClass myClass; // uninitialized if (!isConstructed) { myClass.isConstructed = true; new (&myClass) myClass; atexit(destruct_myClass); return myClass.doCalculation(); } • Racecondition • myClasscouldbe double-constructedand double-destructed
Problems: Multithreading (3) • Proposition • Locking out otherthreads int calculateResult() { Lock myLock(myMutex); // only one thread gets past here static int result = doCalculation(); return result; } • Problem • doCalculation()orany sub-functionofitcouldcallcalculateResult() • Thethreadalreadyhasthe lock, thereforecan enter thesynchronized block andagainseeuninitializedresult!
Outline • Overview • Global Objects • Statics • Initialization • Problems • Ordering • Multithreading • Possible Solutions • AvoidingStatics • Singleton • Schwarz Counter • Spinlocks • Conclusions • Sources
Possible Solutions:AvoidingStatics • Avoidusingstaticswheneverpossible • Usereferencesasparametersinsteadof global variables // Usingstatics • static MyClass myClass; • void myFunction() { • myClass.doCalculation(); • } • int main() { • myFunction(); • } // Usingreferences • void myFunction(MyClass &myClass) { • myClass.calculate(); • } • int main() { • MyClass myClass; • myFunction(myClass); • return 0; • }
Possible Solutions:AvoidingStatics • It‘spossibletousestack variables in main() • A littlebitof a hack • Lifetimeandorderingcontrol // SomeClass.h classSomeClass {…}; • extern SomeClass*g_ptr_someClass; // main.cpp • #include "SomeClass.h" • int main() { • SomeClasso1; • g_ptr_someClass = &o1; • returng_ptr_someClass->func(); • } • Downsides • Inconvenientsyntax (use global variables bypointers) • Loss in efficiency
Possible Solutions: Singleton (1) • Meyer‘s Singleton • Controlovercreation time • Nocontroloverdestruction time (duringprocessshutdown) • IfsomedestructorcallsGetInstance() after thedestructionofs_instance, theprogram will beworkingwith an uninitializedobject, whichisknownas„Dead Reference problem“ • Using a staticlocalobjectis vulnerable toraceconditions in multithreadedenvironments
Possible Solutions: Singleton (2) • Alexandrescu Singleton • Can be made thread-safe • Solves the Dead Reference problem by providing the GetLongevity methods for specification of destruction order • Downsides: • A lot of effort if new singletons are inserted into the system • The programmer provides the ranking values “Easy to get it wrong” and errors are very hard to detect
Possible Solutions: Schwarz Counter • Also knownas „Nifty Counter“ • Usedby Standard C++ iostreamlibrary • Ensuringstaticobjectstobeavailablebeforemainlineexecution, andbeforetheyareusedbyanyotherstaticobjects
Possible Solutions: Schwarz Counter • // Stream.hpp • classStreamInitializer; • classStream { • friendclassStreamInitializer; • public: • Stream() { /* Constructor must becalledbeforeuse. */ } • }; • staticclassStreamInitializer { • public: • StreamInitializer(); • ~StreamInitializer(); • } initializer;
Possible Solutions: Schwarz Counter • The header file of the Stream class has to be included before any member function can be called on the Stream object • This ensures that the constructor of the initializer object is called before the Stream object is used. • // Stream.cpp • staticintnifty_counter; // initializationofthecounter • StreamInitializer::StreamInitializer() { • if (0 == nifty_counter++) • // initializationofthestreamobject‘sstaticmembers • } • StreamInitializer::~StreamInitializer() { • if (0 == --nifty_counter) • // cleaningup • }
Possible Solutions:Spinlocksfor Multithreading • The spinlockitselfiscostly • In mostcasesfunction-localstaticobjectsare not beingaccessedtoooftenbytoomanythreads • The guardedsectionisveryshort • MyClass &getInstance(); // initializationofthecounter • { • staticintguard; // initializedtozero • spin_mutex(&guard); • lock_scope<spin_mutex> lock(smx); • staticMyClassinstance; • returninstance; • }
Outline • Overview • Global Objects • Statics • Initialization • Problems • Ordering • Multithreading • Possible Solutions • AvoidingStatics • Singleton • Schwarz Counter • Spinlocks • Conclusions • Sources
Conclusions • Staticobjectscan bring alongseriousproblems • Avoidthemwheneveryoucan! • Ifreallyneeded, alwaysbesureabout • Scopeandlifetime • Construction Order • Multithreading issues • Possiblesolutionscanbe • Singletons, Schwarz Counter • Lockingwithspinlocks
Sources • M. Wilson, Imperfect C++: Practical Solutions for Real-Life Programming, Addison-Wesley, 2004 • M. Götze, Presentation in the Seminar on Advanced C++ Programming, FAU Erlangen-Nürnberg, 2011 • G. Loganathan, Presentation in the Seminar on Advanced C++ Programming, FAU Erlangen-Nürnberg, 2012 • Prinz, Peter, C++ Lernen und professionell anwenden, MITP-Verlag, 1999 • U. Breymann, C++ Eine Einführung, 5th edition, Hanser Verlag, 1999 • S. Prata, C++: Eine Einführung in die objektorientierte Programmierung, 8th edition, te-wi Verlag, 1992 • Schwarz Counter C++ Idiom https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Nifty_Counter