C++函数中的多线程静态 POD 初始化

C++ multithreaded static POD initialisation within a function

本文关键字:静态 POD 初始化 多线程 函数 C++      更新时间:2023-10-16

我不确定静态 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?

MSVC 2013 不支持"魔术静力学" MSDN : C++11 支持。 我还在较早的时间验证了生成的代码,并确认它不支持它们。

VS2015似乎工作正常(并标记为这样)。

VS2013 中生成的代码与早期代码相同,具有线程不安全机制,用于检测变量是否已构造。 这是必要的。 这个测试+构造对象的时间是比赛发生的时间长度。

一个项目完全建成后,不再进行重建。

我在VS2013中发现了许多编译器问题(例如,在VM中运行时运行时,运行时库中AVX命令的检测不正确),Microsoft建议针对任何已识别的问题升级编译器。Microsoft连接:AVX 生成非法指令

这是我给你的建议。

是否有可能一个线程将 pod.value 设置为 1,但在另一个竞争线程 0 之后将其初始化回 0?

编译器有 3 个计划用于初始化程序中的静态数据。

  • 非常静态的数据
  • 静态数据
  • 非容器数据。

非常静态的数据

当编译器看到一个在编译时可以完全知道的数据结构时,它将在 obj 文件中为该结构创建内存,该文件将为最终文件提供正确的布局。 这不会多次初始化。

静态数据

如果POD结构正在使用编译时不完全已知的信息进行初始化,则将为未知元素创建一个构造函数。 在我确定的情况下

struct memoryAllocator {
void * (*mallocFunction)( size_t size );
int initialized;
}
memoryAllocator alloc { malloc, 1 };

ALLOC初始化时初始化设置为1作为静态数据,然后使用导入的malloc的值在main之前构造。 似乎没有C++要求对象的构造是全有或全无。 这对我来说似乎是一个疏忽。

非容器数据

这初始化为构造函数。 在静态函数中,代码由一个变量保护,该变量描述初始化是否已完成。

通过查看您的代码,您有

  1. 未初始化 POD 结构中的数据
  2. 不是value能够从 1 转换到 0 的编写代码。

在这个术语中,我希望 POD 数据保持未初始化和 0(因为它是静态的),并且构造函数是唯一要调用的项目,并且会将数据修改一次为 1(由于互锁)。