Reputation: 1713
I'm unsure if static POD's may actually be zero initialised multiple times if they are static variables within functions that are called by multiple threads:
void CalledByManyThreads()
{
struct StaticClass
{
struct POD { volatile LONG value; } pod; // Using MSVC specific volatile behaviour - I don't care about std::atomic
StaticClass() // Constructor makes the struct a non-POD so we likely need the extra POD struct for our member data
{
while (pod.value == 0)
if (InterlockedCompareExchange(&pod.value, 0, 1) == 0)
{
// Is it possible that another thread zero initialises pod after we have just set it to 1?
break;
}
}
};
static StaticClass test; // When is test.pod zero initialised in MSVC 2013+?
}
Around this area of functionality there are differences between mandated C++ standards and the actual behaviour of compilers - and I am more interested in the reality of existing compilers from MSVC2013 onwards.
Is it possible that one thread sets pod.value to 1 but that after another competing thread zero initialises it back to 0?
Upvotes: 1
Views: 68
Reputation: 13073
MSVC 2013 does not support "magic statics" MSDN : C++11 support. I have also verified at an earlier time the code generated, and confirmed it does not support them.
VS2015 does appear to work correctly (and marked as such).
The code generated in VS2013 is the same as earlier code, which has a thread-unsafe mechanism for detecting if the variable has been constructed. This is necessary. This test + the time constructing an object is the length of time the race occurs for.
After one item has been completely constructed, there are no further re-constructions.
There are a number of compiler issues I have found with the VS2013 (e.g. incorrect detection of AVX commands in the runtime library, when running in a VM), and Microsoft have recommended for any identified issues to upgrade the compiler. Microsoft connect : AVX generates illegal instruction
That would be my recommendation to you.
Is it possible that one thread sets pod.value to 1 but that after another competing thread zero initialises it back to 0?
The compiler has 3 plans for initializing static data within a program.
When the compiler sees a data structure which can be completely known at compile time, then it will create memory for the structure within the obj file, which will have the correct layout for the final file. This will not get initialized multiple times.
If the POD
structure is being initialized with information which is not completely known at compile time, then a constructor for the unknown element will be created. In the case I have identified
struct memoryAllocator {
void * (*mallocFunction)( size_t size );
int initialized;
}
memoryAllocator alloc { malloc, 1 };
alloc was initialized with initialized set to 1 as static data, and then constructed before main with the value of the imported malloc. There seems to be no C++ requirement that construction of an object is all-or-nothing. Which seems an oversight to me.
This is initialized as a constructor. When in a static function, the code is guarded by a variable which describes if initialization has completed.
From looking at your code, you have
value
is able to transition from 1 to 0.In this term, I would expect the POD data to be left un-initialized and 0 (as it is static), and the constructor is the only item to be called, and will modify data once to 1 (due to the interlocked).
Upvotes: 1