在C/C++中执行"_dl_init"(程序初始化)是单线程的吗

Is execution of `_dl_init` (program initialization) single-threaded in C/C++?

本文关键字:quot 初始化 程序 单线程 init C++ 执行 dl      更新时间:2023-10-16

我有几个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.ccb.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之前初始化非本地静态变量的单个实现,那么您可以确保此初始化将在单个线程中进行。如果你很勇敢,你可以试着理解在任何非初始化或使用与要初始化的变量定义在同一翻译单元中的任何非内联函数或非内联变量之前,它会强烈发生,以及你如何使用它,接受龙隐藏在静态初始化附近的事实,它可能发生在任何线程中。。。