Is local static variable initialization thread-safe in C++11?
The relevant section 6.7:
such a variable is initialized the first time control passes through its declaration; such a variable is considered initialized upon the completion of its initialization. [...] If control enters the declaration concurrently while the variable is being initialized, the concurrent execution shall wait for completion of the initialization.
Then there's a footnote:
The implementation must not introduce any deadlock around execution of the initializer.
So yes, you're safe.
(This says nothing of course about the subsequent access to the variable through the reference.)
Is C++ static member variable initialization thread-safe?
It's more a question of function-scoped static variables vs. every other kind of static variable, rather than scoped vs. globals.
All non-function-scope static variables are constructed before main(), while there is only one active thread. Function-scope static variables are constructed the first time their containing function is called. The standard is silent on the question of how function-level statics are constructed when the function is called on multiple threads. However, every implementation I've worked with uses a lock around the constructor (with a twice-checked flag) to guarantee thread-safety.
Local Static variable initialization is thread safe
Yes, it will be thread safe, but only since C++11. Static variables are initialized in thread safe way, they are often also called magic statics.
For more see here: http://en.cppreference.com/w/cpp/language/storage_duration#Static_local_variables
If multiple threads attempt to initialize the same static local variable concurrently, the initialization occurs exactly once (similar behavior can be obtained for arbitrary functions with std::call_once).
Note: usual implementations of this feature use variants of the double-checked locking pattern, which reduces runtime overhead for already-initialized local statics to a single non-atomic boolean comparison.
Also - in your code you call CreateEmployee(); during initialization of static i
, and CreateEmployee(
also initializes a static variable. This should also be OK, you can find in standard following footnote:
The implementation must not introduce any deadlock around execution of the
initializer.
As to your second question, from the code you have shown I dont see that it is OK to use static variable as a way to gain thread safety.
Are you aware that specifying a variable as static inside function body allows you to assign it only once? This means your CreateEmployee() will always return the same Employee instance.
C++ thready safety of a static member variable
No it is not thread safe insofar there is no built-in mechanism to obviate data races.
static std::atomic<int> m_test;
would be though.
Note that you also have thread_local
as a storage duration too - not of use to you in this instance - but if you had that rather than static
then every thread would get their own m_test
.
Cost of thread-safe local static variable initialization in C++11?
A look at the generated assembler code helps.
Source
#include <vector>
std::vector<int> &get(){
static std::vector<int> v;
return v;
}
int main(){
return get().size();
}
Assembler
std::vector<int, std::allocator<int> >::~vector():
movq (%rdi), %rdi
testq %rdi, %rdi
je .L1
jmp operator delete(void*)
.L1:
rep ret
get():
movzbl guard variable for get()::v(%rip), %eax
testb %al, %al
je .L15
movl get()::v, %eax
ret
.L15:
subq $8, %rsp
movl guard variable for get()::v, %edi
call __cxa_guard_acquire
testl %eax, %eax
je .L6
movl guard variable for get()::v, %edi
movq $0, get()::v(%rip)
movq $0, get()::v+8(%rip)
movq $0, get()::v+16(%rip)
call __cxa_guard_release
movl $__dso_handle, %edx
movl get()::v, %esi
movl std::vector<int, std::allocator<int> >::~vector(), %edi
call __cxa_atexit
.L6:
movl get()::v, %eax
addq $8, %rsp
ret
main:
subq $8, %rsp
call get()
movq 8(%rax), %rdx
subq (%rax), %rdx
addq $8, %rsp
movq %rdx, %rax
sarq $2, %rax
ret
Compared to
Source
#include <vector>
static std::vector<int> v;
std::vector<int> &get(){
return v;
}
int main(){
return get().size();
}
Assembler
std::vector<int, std::allocator<int> >::~vector():
movq (%rdi), %rdi
testq %rdi, %rdi
je .L1
jmp operator delete(void*)
.L1:
rep ret
get():
movl v, %eax
ret
main:
movq v+8(%rip), %rax
subq v(%rip), %rax
sarq $2, %rax
ret
movl $__dso_handle, %edx
movl v, %esi
movl std::vector<int, std::allocator<int> >::~vector(), %edi
movq $0, v(%rip)
movq $0, v+8(%rip)
movq $0, v+16(%rip)
jmp __cxa_atexit
I'm not that great with assembler, but I can see that in the first version v
has a lock around it and get
is not inlined whereas in the second version get
is essentially gone.
You can play around with various compilers and optimization flags, but it seems no compiler is able to inline or optimize out the locks, even though the program is obviously single threaded.
You can add static
to get
which makes gcc inline get
while preserving the lock.
To know how much these locks and additional instructions cost for your compiler, flags, platform and surrounding code you would need to make a proper benchmark.
I would expect the locks to have some overhead and be significantly slower than the inlined code, which becomes insignificant when you actually do work with the vector, but you can never be sure without measuring.
C++: Is initializing a static local variable with a IIFE thread-safe?
Yes. C++11 (and above) guarantees no data races between multiple threads trying to initialize a static local variable. If the code inside your lambda is thread-safe, the initialization will be as well.
Using a lambda, function call, or constructor doesn't change the thread-safety of the initialization.
C++11 Singleton. Static variable is thread safe? Why?
In C++11 (and forward), the construction of the function local static AppSettings
is guaranteed to be thread-safe. Note: Visual Studio did not implement this aspect of C++11 until VS-2015.
The compiler will lay down a hidden flag along side of AppSettings
that indicates whether it is:
- Not constructed.
- Being constructed.
- Is constructed.
The first thread through will find the flag set to "not constructed" and attempt to construct the object. Upon successful construction the flag will be set to "is constructed". If another thread comes along and finds the flag set to "being constructed", it will wait until the flag is set to "is constructed".
If the construction fails with an exception, the flag will be set to "not constructed", and construction will be retried on the next pass through (either on the same thread or a different thread).
The object instance
will remain constructed for the remainder of your program, until main()
returns, at which time instance
will be destructed.
Every time any thread of execution passes through AppSettings::GetInstance()
, it will reference the exact same object.
In C++98/03, the construction was not guaranteed to be thread safe.
If the constructor of AppSettings
recursively enters AppSettings::GetInstance()
, the behavior is undefined.
If the compiler can see how to construct instance
"at compile time", it is allowed to.
If AppSettings
has a constexpr
constructor (the one used to construct instance
), and the instance
is qualified with constexpr
, the compiler is required to construct instance
at compile time. If instance
is constructed at compile time, the "not-constructed/constructed" flag will be optimized away.
Related Topics
Implicit VS Explicit Conversion
Is Make_Shared Really More Efficient Than New
How to Build Boost Version 1.58.0 Using Visual Studio 2015 (Enterprise)
Static and Dynamic/Shared Linking with Mingw
Std::Lexical_Cast - Is There Such a Thing
C++ Format MACro/Inline Ostringstream
Safer But Easy-To-Use and Flexible C++ Alternative to Sscanf()
Performance Difference Between C and C++ Style File Io
Gcc: Difference Between -O3 and -Os
Std::Forward_List and Std::Forward_List::Push_Back
Is a Linked-List Implementation Without Using Pointers Possible or Not
When Should Functions Be Member Functions
Why Does Valgrind Say Basic Sdl Program Is Leaking Memory