Let's say, that this is a function that serves several threads. They read kHKeys
that is not protected since Read-Read from the same memory-address is not a data-race.
But, on the 1st Read, kHKeys
is constructed. It is possible that during construction, another thread enters reentrantFunction function.
Is it necessary to construct kHKeys
before unleashing the threads that call simultaneously the reentrantFunction ?
Example:
int reentrantFunction(const std::wstring& key_parent_c)
{
// const 'static' means that kHKeys is constructed only once —
// The 1st the function is run — and put into a shared memory space.
// Otherwise, kHKeys is local and it must be constructed each time the function is called.
const static std::map<std::wstring, HKEY> kHKeys{ { L"HKEY_CURRENT_USER", HKEY_CURRENT_USER } ,
{ L"HKEY_LOCAL_MACHINE", HKEY_LOCAL_MACHINE } , { L"HKEY_CLASSES_ROOT", HKEY_CLASSES_ROOT } ,
{ L"HKEY_CURRENT_CONFIG", HKEY_CURRENT_CONFIG } , { L"HKEY_CURRENT_USER_LOCAL_SETTINGS", HKEY_CURRENT_USER_LOCAL_SETTINGS } ,
{ L"HKEY_PERFORMANCE_DATA", HKEY_PERFORMANCE_DATA } , { L"HKEY_PERFORMANCE_NLSTEXT", HKEY_PERFORMANCE_NLSTEXT } ,
{ L"HKEY_PERFORMANCE_TEXT", HKEY_PERFORMANCE_TEXT } , { L"HKEY_USERS", HKEY_USERS } };
// Use kHKeys
It is not a must to construct kHKeys
before the threads start to use reentrantFunction
.
As you can see here: static local variables, since C++11 is it guaranteed by the standard that a static local variable will be initialized only once. There is a specific note regarding locks that can be applied to ensure single initialazion in a multi threaded environment:
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.
However - if you use a static variable that requires a relatively long initialization (not the case in your example), and your threads are required to perform according to some realtime requirements (with minimum delay), you can consider to do it in separate initialization phase, before the threads start to run.