如果静态POD是多个线程调用的函数中的静态变量,我不确定静态POD是否实际上可以多次初始化为零:
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+?
}
围绕这个功能领域,强制性C ++标准与编译器的实际行为之间存在差异 - 我对MSVC2013以后的现有编译器的实际情况更感兴趣。
是否有可能一个线程将pod.value设置为1但是在另一个竞争线程零之后将其初始化为0?
答案 0 :(得分:1)
MSVC 2013不支持“魔法静态”MSDN : C++11 support。我还在较早时间验证了生成的代码,并确认它不支持它们。
VS2015似乎确实正常工作(并标记为这样)。
VS2013中生成的代码与早期代码相同,后者具有线程不安全机制,用于检测变量是否已构造。这是必要的。此测试+构建对象的时间是比赛发生的时间长度。
完成一个项目后,没有进一步的重建。
我在VS2013中发现了许多编译器问题(例如,在运行时在VM中运行时错误检测运行时库中的AVX命令),Microsoft已建议任何已识别的问题升级编译器。 Microsoft connect : AVX generates illegal instruction
这是我对你的推荐。
是否有可能一个线程将pod.value设置为1但是在另一个竞争线程零之后将其初始化为0?
编译器有3个计划来初始化程序中的静态数据。
当编译器看到一个可以在编译时完全知道的数据结构时,它将为obj文件中的结构创建内存,该文件将具有最终文件的正确布局。这不会多次初始化。
如果使用在编译时未完全知道的信息初始化POD
结构,则将创建未知元素的构造函数。在我确定的情况下
struct memoryAllocator {
void * (*mallocFunction)( size_t size );
int initialized;
}
memoryAllocator alloc { malloc, 1 };
alloc初始化为初始化设置为1作为静态数据,然后在main之前用导入的malloc的值构造。似乎没有C ++要求构造对象是全有或全无。这似乎是对我的疏忽。
这被初始化为构造函数。在静态函数中,代码由变量保护,该变量描述初始化是否已完成。
从查看代码开始,
value
能够从1过渡到0的代码。在这个术语中,我希望POD数据保持未初始化和0(因为它是静态的),并且构造函数是唯一要调用的项目,并且将数据修改为1(由于互锁)。