C++ 静态变量的初始化线程安全问题
1. 静态变量的初始化线程安全问题
C++11 规定了局部static变量的线程安全,实现上应该是类似std::call_once
的实现,我估计基本上就是基于cas的spin-lock,这里当然可以根据编译器不同有不同的实现。
按照静态变量初始化的时机,初始化过程可分为:编译时初始化和加载(运行)时初始化,前者主要发生在静态常量的编译过程中,如程序中“static int a = 3”
因为此处3为常量,编译时就能确定,因此这里就发生的是编译时初始化,反之,如果不是编译时初始化,那就必定进行的是加载时初始化
2. 静态变量的初始化顺序
对于已经初始化的全局和静态变量时存放在可执行文件的数据段(.data),对于未初始化的全局和静态变量,则在BSS段中。
从可执行程序的角度来说,如果一个数据未被初始化,就不需要为其分配空间,所以.data 和.bss 的区别就是 .bss 并不占用可执行文件的大小,仅仅记录需要用多少空间来存储这些未初始化的数据,而不分配实际空间,编译器往往通过memset(bss_str, len, 0)进行初始化。
.bss段什么时候会进行真正的初始化呢?记得一开始接触全局变量和静态变量的时候,书上就有提到,在可执行程序执行之前(main函数运行之前),会进行一些初始化操作,.bss就是在这个阶段进行初始化的。也就是说.data和.bss段的数据,在main()函数执行之前就初始化完成,那么,可以得出的结论是这部分数据不存在多线程竞争的问题(main()函数执行前还不存在多线程现象)。
C++标准规定,在同一个编译单元中,对全局变量或者静态变量的初始化顺序与其定义顺序一致
既然出现了因为不同编译单元中的静态变量初始化导致,那么就需要针对性的解决这个问题,通常有如下几个方案:
-
将所有的静态全局变量放在一个编译单元中(如果涉及到依赖的话,需要修改顺序)。
-
强制编译器在编译阶段进行初始化,通常有constexpr和constinit两种。
-
Initialization On First Use,即在使用时候,通过函数获取静态对象的方式进行初始化。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)