gpt4 book ai didi

c++ - 全局静态初始化线程

转载 作者:太空狗 更新时间:2023-10-29 21:01:24 25 4
gpt4 key购买 nike

我有一个使用互斥体保护的集合。初始化后它只会被读取,所以我不需要互斥量。

集合在全局静态初始化器中初始化和填充。我知道在单个翻译单元内保证全局静态初始化。是否可以保证全局静态初始化将是单线程的?


我有一个受 Schwarz 计数器保护并由其他静态对象的构造函数填充的静态集合。容器与互斥量相关联。鉴于集合在 main 启动后是只读的,如果我能保证在单个线程中调用静态构造函数,我想摆脱互斥体。

我的理解是,静态初始化顺序通常在单个翻译单元内明确定义,但在翻译单元之间未指定。该标准是否允许静态对象由不同运行时提供的线程初始化/构造?


施瓦茨计数器:

头文件:

struct Init
{
Init();
~Init();
};
namespace
{
Init _init;
}
extern std::map<int, std::unique_ptr<...>> &protected;

源文件:

namespace
{
int init_count;
std::aligned_storage<sizeof(std::map<int, std::unique_ptr<...>>), alignof(std::map<int, std::unique_ptr<...>>>)> protected_storage;
}
std::map<int, std::uniqe_ptr<...>> &protected = *reinterpret_cast<std::map<int, std::unique_ptr<...>> *>(&protected_storage);
Init::Init()
{
if (!init_counter++)
{
new(&protected_storage) std::map<int, std::unique_ptr<...>>();
}
}
Init::~Init()
{
if (!--init_counter)
{
protected.~std::map<int, std::unique_ptr<...>>();
}
}

集合人口:

struct helper
{
helper(...)
{
protected.insert(std::make_pair(...));
}
};

扩展了一个宏来创建 helper 的静态实例。

最佳答案

Is there any guarantee that global static initialization will be single threaded?

你的意思是动态初始化。不,明确不保证单线程初始化。

从 3.6.2 开始:

If a program starts a thread (30.3), the subsequent initialization of a variable is unsequenced with respect to the initialization of a variable defined in a different translation unit. Otherwise, the initialization of a variable is indeterminately sequenced with respect to the initialization of a variable defined in a different translation unit. If a program starts a thread, the subsequent unordered initialization of a variable is unsequenced with respect to every other dynamic initialization. Otherwise, the unordered initialization of a variable is indeterminately sequenced with respect to every other dynamic initialization

因此,如果您在程序中启动一个线程,那么理论上来自两个不同 TU 的两个不同全局变量可以让它们的构造函数同时从两个不同线程运行。

处理这些问题的最佳方法是将静态存储持续时间变量包装为以下“单例模式”中的局部静态变量:

const T& f()
{
static T t(a,b,c);
return t;
}

最新的标准保证t的构造是线程安全的,所以你根本不需要互斥量(至少不需要明确指定,编译器会为你生成守卫) .

作为一个额外的好处,该对象是在第一次调用 f 时“延迟”构建的,因此您无需担心初始化顺序。如果多个这样的单例在它们的构造函数中相互调用(当然前提是依赖关系是非循环的),它们将按工作顺序初始化。非局部变量不是这种情况。

关于c++ - 全局静态初始化线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18542804/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com