Statics in Depth

1 / 32

# Statics in Depth - PowerPoint PPT Presentation

Statics in Depth. Markus Götze FAU Erlangen Nürnberg Seminar Advanced C++ Programming 20.06.2011. Motivation (1). Personal flashback → C : Variable whose value must be remembered Global Static Variable. static int someVar ; void incSomeVar (); int main() { incSomeVar (); //...

I am the owner, or an agent authorized to act on behalf of the owner, of the copyrighted work described.

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.

- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript

### Statics in Depth

Markus Götze

FAU Erlangen Nürnberg

20.06.2011

Motivation (1)

Personal flashback → C:

Variable whose value must be remembered

Global Static Variable

staticintsomeVar;

voidincSomeVar();

intmain()

{

incSomeVar();

//...

incSomeVar();

//...

printf("%d\n",someVar);

exit(0);

}

voidincSomeVar()

{

++someVar;

}

Motivation (2)

This may raise some questions:

namespacenSpace

{

inlineintretFour()

{

return4;

}

intglobal1=0;

intglobal2;

intglobal3=42;

intglobal4=retFour();

}

• global1 → clear
• what value does global2 have?
• when is global3 set to 42?
• will initialization of global4 even result in a
• compiler error?
Outline
• Motivation
• Problems
• Solutions approaches
• Conclusion
Outline
• Motivation
• Problems
• Order of Construction
• Race conditions with Dynamic Initialization of Static Variable
• Solutions approaches
• Conclusion
Problems – Order of Construction (1)

ClassMyClass;

externMyClassmyFourthClass;

MyClassmyFirstClass(“1”);

MyClassmySecondClass(myFirstClass);

MyClassmyThirdClass(myFourthClass);

MyClassmyFourthClass(“4“);

• Objects are created by order of definition, not declaration
Problems – Order of Construction (2)

classMyClass

{

private:

inti;

public:

MyClass(intnum)

{

std::cout<<"In Constructor"<<std::endl;

i=num;

}

}

• one famous static object is std::cout
• does cout exist when static object MyClass is created?

//myClass1.cpp

MyClassmyFirstClass();

MyClassmySecondClass();

//myClass2.cpp

MyClassmyThirdClass();

//myClass3.cpp

MyClassmyFourthClass();

//Makefile

myClass:

\$(CXX)myClass1.cppmyClass2.cppmyClass3.cpp-omyClass

Problems – Race Conditions (1)
• Especially static members result in race conditions
• The following example will show what can go wrong in detail:

intcalculateResult()

{

staticboolresult_computed=false;

staticintresult;

if(!result_computed)

{

result_computed=true;

result=calculateSomething();

}

returnresult;

}

intcalculateResult()

{

staticintresult=

calculateSomething();

returnresult;

}

• If one thread will be pre-empted after having set result_computed to true,
• next thread will pass if-block and see uninitialized variable
Problems – Race Conditions (2)

classMyClass{...};

intcalculateResult()

{

staticboolmyClass_constructed=false;

staticMyClassmyClass;// uninitialized

if(!myClass_constructed)

{

myClass.constructed=true;

new(&myClass)myClass;

atexit(DestructmyClass)

}

returnmyClass.calculateSomething();

}

classMyClass{...};

intcalculateResult()

{

staticMyClassmyClass;

returnmyClass.

calculateSomething();

}

• as before, myClass could be used before it has been initialized
• additionally, myClass could be double-constructed and double-destructed
Problems – Race Conditions (3)

classMyClass{...};

intcalculateResult()

{

staticcharconstructed=0;

staticuninitializedMyClassmC1;

if(!(constructed&1)){

constructed|=1;

new(&mC1)MyClass;

atexit(DestructmC1);

}

staticuninitializedMyClass mC2;

if(!(constructed&2)){

constructed|=2;

new(&mC2)MyClass;

atexit(DestructmC2);

}

returnmC1.calculateSomething()+mC2.calculateSomething();

}

classMyClass{...};

intcalculateResult()

{

staticMyClassmC1;

staticMyClassmC2;

returnmC1.calculateSomething() +mC2.calculateSomething();

}

• one bitfield for both _constructed
• variables
• multiple RMS-operations on the same
• data-structure
• still race conditions here
Problems – Race Conditions (4)

intcalculateResult()

{

lock();

staticintresult=calculateSomething();

unlock();

returnresult;

}

• Proposition: put computation in a synchronized block
• Problem: What if calculateSomething() somewhere somehow calls
• calculateResult() ?
• → the thread already has the lock, may enter the critical section and
• once again see an uninitialized object result
Outline
• Motivation
• Problems
• Solutions approaches
• Conclusion
Outline
• Motivation
• Problems
• Solutions approaches
• Avoid statics when possible
• Singletons
• Schwarz Counter
• Fight race-conditions
• Conclusion
Solution approaches – Avoid Statics
• Generally speaking, avoid static when you can!
• Use references as parameters instead of global variables

staticMyClassmyClass;

voidsomeFunc()

{

myClass.doSomething();

}

intmain()

{

//...

someFunc();

}

voidsomeFunc(MyClass*myClass)

{

myClass->doSomething();

}

intmain()

{

MyClassmyClass;

someFunc(&myClass);

}

Solution approaches – Avoid Statics
• Generally speaking, avoid static when you can!
• Change global objects to stack objects within main (kind of a hack)
• We gain full control over lifetime, but have to use all global variables by pointer
• Loss in efficiency
• Inconvenient syntax

//main.cpp

#include "MyClass1.h"

#include "MyClass2.h"

intmain()

{

MyClassmyClass;

p_myClass=&myClass;

p_myClass->doSomething();

return0;

}

//MyClass1.h

classMyClass1

{

//...

voiddoSomething(){...}

};

externMyClass1*p_myClass1;

Solution Approaches – Singleton (1)
• Looking back at techniques we already learned, one idiom lets us gain control over lifetime
• Singleton!
• Let‘s look back for a short moment:
Solution Approaches – Singleton (2)

Meyers Singleton

classMyClass

{

public:

MyClass&getInstance()

{

staticMyClassinstance;

returninstance;

}

private:

MyClass(constMyClass&other);

MyClass&operator=(constMyClass&other);

}

• Object is created first time getInstance() is called
• → we have control over creation time of object
• we still do not have control over destruction time; only guarantee: „during process
• shutdown“
• local static object -> race conditions!
Solution Approaches – Singleton (3)

Alexandrescu Singleton

classMyClass

{

public:

MyClass&getInstance()

{

if(instance==null)

{

instance=newMyClass();

Infrastructure::register(instance,...);

}

return*instance;

}

private:

staticMyClass*instance;

MyClass(constMyClass&other);

MyClass&operator=(constMyClass&other);

}

Solution Approaches – Singleton (3)

Alexandrescu Singleton

• by providing the GetLongevity methods, the programmer can specify the
• relative destruction order
• Downsides:
• a lot of effort if new Singletons are inserted into the system
• „easy to get it wrong“
• errors are very hard to detect

inlineunsignedintGetLongevity(MyClass*){return2;}

Solution Approaches – Schwarz Counter (1)

//MyClass.h

classMyClass{...};

externMyClass*p_myClass;

classMyClass_init

{

private:

staticintinit_count;//zero-initialized

public:

MyClass_init();

~MyClass_init();

};

staticMyClass_initmyClass_init;// file static scope

namespace{MyClass_initmyClass_init;}//anonymous namespace

• myClass_init has file static scope (anonymous namespace), so there will exist as
• many variables as files that include MyClass.h
• only one init_count
Solution Approaches – Schwarz Counter (2)

//MyClass_initc\'tor und d\'tor

MyClass*p_myClass;

MyClass_init::MyClass_init()

{

if(++init_count>0)

return;

p_myClass=newMyClass;

// other needed initializations

}

MyClass_init::~MyClass_init()

{

if(--init_counter>0)

return;

deletep_myClass;

// other destruction

}

• use a reference count to gain control over time of destruction
Solution Approaches – Schwarz Counter (3)

// OtherClass.h

#include "MyClass.h"

classOtherClass

{

private:

MyClassmyClass;

public:

// ...

};

• Classes must be declared before objects or members of that type can be
• declared, meaning:
• MyClass.h is included above class definition of OtherClass
• Declaration of MyClass_init will therefore always happen before any
• OtherClass object is created
• since construction order is reversed for destruction, MyClass_init will
• always be destructed after OtherClass
Solution Approaches – Schwarz Counter (4)
• Special Case: class C wants to make use of MyClass without containing any instance of it
• For example: Class wants to use I/O without containing a stream object

//C.h

//...

classC_init

{

private:

staticintinit_count;

public:

C_init();

~C_init();

};

staticC_initC_init;

Solution Approaches – Schwarz Counter (5)

//C_initc\'tor and d\'tor

#include "C.h"

#include "MyClass.h"

staticMyClass_init*minit;

C_init::C_init()

{

if(++init_count>1)

return;

minit=newMyClass_init;

}

C::init::~C_init()

{

if(--init_counter>0)

deleteminit;

}

• C_init is declared higher in file than any declaration
• of C, so C_init constructor will be called before C
• constructor
• That guarantees that MyClass will be initialized by
• MyClass_init before any C constructor
Solution approaches – Fighting race conditions (1)
• Going back to race conditions

MyClass&getInstance()

{

staticbool__bMyClassInitialized__=false;

staticbyte__myClassBytes__[sizeof(MyClass)];

if(!__bMyClassInitialized__)

{

new(__myClassBytes__)MyClass();

__bMyClassInitialized__=true;

}

return*reinterpret_cast<MyClass*>

(__myClassBytes__);

}

MyClass&getInstance()

{

staticMyClassmyClass;

returnmyClass;

}

• two or more threads could see __bMyClassInitiliazed__ is false and go on to
• construct it
Solution approaches – Fighting race conditions (2)

MyClass&getInstance()

{

staticintguard;// zero-initialized

spin_mutex(&guard);

lock_scope<spin_mutex>lock(smx);

staticMyClassinstance;

returninstance;

}

• Best solution here: use a spinlock
• use of spinlock is costly, but only if:
• high degree of quarrel
• guarded section is long
• both cases here are tolerable
Outline
• Motivation
• Problems
• Solutions approaches
• Conclusion
Outline
• Motivation
• Problems
• Solutions approaches
• Conclusion
Conclusion
• Static objects bring along very serious problems!
• Hence avoid them where you can!
• If you must use them, remember to solve the two problems for your very special problem
• Construction order