在C/C++中执行"_dl_init"(程序初始化)是单线程的吗
Is execution of `_dl_init` (program initialization) single-threaded in C/C++?
我有几个C++源文件,其中一些数据/回调被注册在标头中的映射中。
// foo.h
class Foo final {
public:
static void Register(...) { ... }
private:
inline static std::map<...> g_map{};
};
// a.cc, b.cc, etc.
#include "foo.h"
namespace {
struct Init {
Init() {
Foo::Register(...);
}
};
Init g_init{}; // the inversion-of-control trick
}
那么有必要使用锁来保护g_map
吗?我的直觉是_dl_init
(在main
之前的运行时调用(的执行是单线程的,尽管顺序是a.cc
、b.cc
。。。是未知的,对吗?
如果非本地静态变量在main启动之前初始化,那么它们将在[basic.start.main]中定义的线程中初始化(参考C++20的草案n4659(:
执行一个程序会启动一个执行主线程(4.7,33.3(,在该线程中调用主函数,并在其中初始化(6.6.2(和销毁(6.6.4(静态存储持续时间的变量
但是C++对静态变量的初始化并没有那么简单:-(.相同的草案稍后在[basic.start.dynamic]§4(强调我的(:
它是实现定义的,是否使用static对非本地非内联变量进行动态初始化存储持续时间在main的第一个语句之前排序,或者被推迟。如果延期发生在任何非初始化odr使用中定义的任何非内联函数或非内联变量之前与要初始化的变量相同的转换单元它是定义的实现,其中线程和在程序中的哪些点发生这种延迟的动态初始化。
我的理解是,该标准尽最大努力防止程序员在初始化静态变量时做出假设。如果实现是程序员友好的,它将在单个线程中的main之前初始化所有非本地静态变量-标准允许这样做。但不幸的是,它将是不可移植的,因为标准没有强制要求它。
TL/DR:如果您的目标是一个保证在调用main之前初始化非本地静态变量的单个实现,那么您可以确保此初始化将在单个线程中进行。如果你很勇敢,你可以试着理解在任何非初始化或使用与要初始化的变量定义在同一翻译单元中的任何非内联函数或非内联变量之前,它会强烈发生,以及你如何使用它,接受龙隐藏在静态初始化附近的事实,它可能发生在任何线程中。。。
- 是否可以初始化不可复制类型的成员变量(或基类)
- C++使用整数的压缩数组初始化对象
- C++初始化基类
- 多成员Constexpr结构初始化
- 复制列表初始化的隐式转换的等级是多少
- 内联映射初始化的动态atexit析构函数崩溃
- 如何在C++中初始化嵌套类中的2个memeber
- 如何声明特征矩阵,然后通过嵌套循环初始化它
- 没有用于初始化C++中的变量模板的匹配构造函数
- 在未初始化映射的情况下,将值插入到映射的映射中
- C++成员初始化
- 为什么在C++中首先初始化成员类
- 同时具有"聚合初始化"和"模板推导"
- 初始化具有非默认构造函数的std::数组项的更好方法
- 是否可以在编译时初始化数组,以便在运行时不会花费时间?
- 我可以使用条件运算符初始化C风格的字符串文字吗
- 在C和C++中初始化结构中的数组
- 标准是否使用多余的大括号(例如 T{{{10}}})定义列表初始化?
- 在函数内部的声明中初始化数组,并在外部使用它
- 继承:构造函数,初始化C++11中基类的类C数组成员