问题描述
cppreference 在 thread_local
变量上声明以下内容
对象的存储在线程开始时分配,在线程结束时释放。每个线程都有自己的对象实例。只有声明为 thread_local 的对象具有此存储持续时间。
我考虑使用在共享库中声明的 thread_local static
成员变量,该变量在运行时通过 dlopen
/ LoadLibrary
加载。由于完全有可能在加载这个库的时间点已经有相当多的线程在运行,并且其中一些线程稍后将访问该变量,我想知道如果在线程开始时分配存储,这是如何工作的?如果在创建线程的时间点程序中不存在该变量,则这显然无法按照那里的说明工作。此外,如果一个进程正在运行,这似乎是一种资源浪费。如果只有少数线程实际访问该变量,则 100 个线程将为每个线程创建该线程局部变量的实例。
那么,这里的文档是否不正确,或者我在这里尝试的内容是否有可能导致未定义的行为?如果文档完全不正确,我在哪里可以找到对现实中可以预期的可靠描述?如果它是实现定义的,我特别感兴趣的是 clang 如何在 macOS 和 Windows 上处理它。
解决方法
cppreference 所说的是意译。 the standard 中的实际内容是
所有使用 thread_local
关键字声明的变量都有线程存储持续时间。这些的存储
实体在创建它们的线程期间持续存在。有一个不同的对象或引用
每个线程,并且使用声明的名称是指与当前线程关联的实体。
那里没有关于存储何时被分配的信息,只是它在线程的持续时间内持续。这意味着它可以在创建线程时分配,或者在第一次使用变量时分配,或者可能是两者的组合。
在分配存储时,可能不会构造变量(我假设这就是您说“创建实例”时的意思)。这取决于变量的定义位置和方式。但是,如果它被构造,它不会被销毁,直到线程结束。
支持通过 dlopen
或 LoadLibrary
动态加载库是编译器/平台扩展,而不是语言的一部分。它与 thread_local
的交互方式也将取决于平台。