📌 非自动变量初始化
C++ 和 C thread_local
的区别
- C++ 支持使用非常量表达式对全局或静态变量初始化 1。对于
static
local 2 /thread_local
变量而言,这项功能需要在访问前检查变量是否已经完成初始化,thread_local
初始化不需要线程间同步,而static
local 变量的访问过程需要线程间的同步(__cxa_guard_acquire
和__cxa_guard_release
)。 - C++ 的
thread_local
变量在函数作用域中自动具有static
属性 3,而 C 要手动加。在 C 语言中,函数中的thread_local
必须和extern
或者static
之一一起使用,例子为 https://godbolt.org/z/eKz71xh7a 。 - C 的
thread_local
在 C23 之前是个宏。
从代价上来看 C++ 的几种变量初始化
- 首先,不需要函数初始化的在编译期间就能完成工作,没有代价。所以以下讨论的都是通过函数或构造函数来初始化的变量。
- 其次,函数内 (static) thread_local 变量只需要在使用前检查一下,构造和使用都不用同步,代价很小。函数内 static 变量的构造和使用则需要线程之间同步。
- 函数外定义的普通变量和 thread_local 变量都不需要任何同步就能在静态初始化阶段完成初始化,使用时也不需要检查。
- 函数外定义的 inline 变量(C++17)在使用时不需要同步,但是在初始化的时候要检查是否已经初始化完成(为此有个 guard variable 标记)。见 https://godbolt.org/z/hYMjdbsxj ,这可能是因为 inline 变量可能被多个地方使用,每个地方都要提防重复初始化。
全局 (和 static) 变量
最外围定义域定义的变量,可以具有 static 属性也可以没有。
不支持非常量初始化表达式(C 模型)
编译器会抱怨:initializer element is not constant。
支持非常量初始化表达式,但只对对象生效(Cfront 1.0 模型)
在用户程序真正运行前插入一段静态变量初始化代码。