【发布时间】:2013-09-03 18:25:08
【问题描述】:
我有一个用互斥锁保护的集合。初始化后它只会被读取,所以我不需要互斥体。
集合在全局静态初始化器中被初始化和填充。我知道在单个翻译单元中保证全局静态初始化。是否保证全局静态初始化是单线程的?
我有一个受 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(...));
}
};
一个宏被展开,它创建了帮助器的静态实例。
【问题讨论】:
-
在 C++11 中,静态初始化不会引入数据竞争。
-
静态初始化是零初始化或常量初始化。我认为您在多线程和单线程 static init(非局部变量)之间不会有任何明显的差异。
-
我们真的是在谈论全局静态初始化器,还是我们也在考虑静态对象的构造器?
-
@KerrekSB 是的,但是您最初的评论指的是什么?如果程序启动线程(因此可能存在数据竞争 AFAIK),则在不同 TU 中具有有序初始化的变量的动态初始化可能是无序的。
-
@DyP:好吧,我的意思是(在第一条评论中)“初始化具有静态存储持续时间的对象”。那可能令人困惑。 “静态”意味着太多的东西:-S