statics in depth
Download
Skip this Video
Download Presentation
Statics in Depth

Loading in 2 Seconds...

play fullscreen
1 / 32

Statics in Depth - PowerPoint PPT Presentation


  • 150 Views
  • Uploaded on

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 (); //...

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

PowerPoint Slideshow about ' Statics in Depth' - aden


An Image/Link below is provided (as is) to download presentation

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

Statics in Depth

Markus Götze

FAU Erlangen Nürnberg

Seminar Advanced C++ Programming

20.06.2011

motivation 1
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
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
Outline
  • Motivation
  • Problems
  • Solutions approaches
  • Conclusion
outline1
Outline
  • Motivation
  • Problems
    • Order of Construction
    • Compiler/Linker Depended Ordering
    • Race conditions with Dynamic Initialization of Static Variable
  • Solutions approaches
  • Conclusion
problems order of construction 1
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
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?
problems compiler linker dependant ordering
Problems – Compiler/Linker dependant ordering

//myClass1.cpp

MyClassmyFirstClass();

MyClassmySecondClass();

//myClass2.cpp

MyClassmyThirdClass();

//myClass3.cpp

MyClassmyFourthClass();

//Makefile

myClass:

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

problems race conditions 1
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
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
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
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
outline2
Outline
  • Motivation
  • Problems
  • Solutions approaches
  • Conclusion
outline3
Outline
  • Motivation
  • Problems
  • Solutions approaches
    • Avoid statics when possible
    • Singletons
    • Schwarz Counter
    • Fight race-conditions
  • Conclusion
solution approaches avoid statics
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 statics1
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
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
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“
  • This may lead to Dead Reference Problem
  • local static object -> race conditions!
solution approaches singleton 3
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 31
Solution Approaches – Singleton (3)

Alexandrescu Singleton

  • This singleton can be made thread-safe
  • 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
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
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
  • this needs to be made thread-safe (like Alexandrescu Singleton)
solution approaches schwarz counter 3
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
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
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
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
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
outline4
Outline
  • Motivation
  • Problems
  • Solutions approaches
  • Conclusion
outline5
Outline
  • Motivation
  • Problems
  • Solutions approaches
  • Conclusion
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
    • Thread safety
  • Possible solutions to these problems may be
    • Singletons, Schwarz Counter
    • Suitable lock mechanisms, for example spinlock
references
References
  • Matthew Wilson “Imperfect C++, Practical Solutions for Real-Life Programming”
  • Stephen C. Dewhurst “C++ Gotchas, Avoiding Common Problems in Coding and Design”
  • Stanley B. Lippman “C++ Gems”
  • http://blogs.msdn.com/b/oldnewthing/archive/2004/03/08/85901.aspx
  • http://en.allexperts.com/q/C-1040/Constructors-Global-Object.htm
  • Florian Krautwurm „C++ Design Patterns: Singleton in Detail“
ad