Shared Data Initialization
-
Global variable
- Accessible to all code in the program
-
Static variable at namespace scope
- Accessible to all code in the translation unit
-
Class member which is declared static
- Potentially accessible to code which calls its member functions
- If public, accessible to all code
-
Local variable which is declared static
- Accessible to all code which calls that function
-
Global variable, Static variable at namespace scope, Static data member of class:
- All are initialized when the program starts
- At that point, only one thread is running
- There cannot be a data race
Static Local Variable
- Initialized after the program starts
- When the declaration is reached
void func() {
// static local variable
static std::string str("xyz");
}
- Two or more threads may call the constructor concurrently
- Is there a data race?
Static Local Variable Initialization before C++11
-
No language support
- The behavior was undefined
-
Lock a mutex?
- Required on every pass through the declaration
- Very inefficient
Static Local Variable Initialization in C++11
-
The behavior is now well-defined
-
Only one thread can initialize the variable
- Any other thread that reaches the declaration is blocked
- Must wait until the first thread has finished initializing the variable
- The threads are synchronized by the implementation
- No data race
-
Subsequent modifications
- The usual rules for shared data
- There will be a data race, unless we protect against one
Singleton Class
-
Used to implement the Singleon design pattern
-
A singleton class has only a single instance
- e.g. a logger class that maintains an audit trail
-
Its constructor is private
-
The copy and move operators are deleted
- The program cannot create more objects
-
A static member function returns the unique instance
- If the instance does not already exist, it is created and initialized
- Otherwise, the existing object is returned
Classic Singleton Implementation
class Singleton {
// Pointer to the unique instance
static Singleton *single;
public:
// Static member function which returns the unique instance
static Singleton* get_singleton() {
if (single == nullptr)
single = new Singleton;
return single;
}
// Class functionality
}
- This has a data race, in a multi threaded program, instead of getting a unique object, we have several different objects.
C++11 Singleton Implementation
class Singleton {
// Class functionality
}
Singleton& get_singleton() {
// Initialized by the first thread that executes this code
static Singleton single;
return single;
}
- The first thread to reach the definition creates the unique instance
- Subsequent threads use the object created by the first thread
- The object remains in existence until the program terminates