1. 静态变量的初始化线程安全问题
C++的局部static变量,是预先在静态存储区分配了内存,然后在第一次执行到这里的时候进行初始化。
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++标准规定,在同一个编译单元中,对全局变量或者静态变量的初始化顺序与其定义顺序一致。但是对于不同的编译单元中的静态变量的初始化顺序,标准没有做规定,也就是说假如两个全局静态变量A和B分别存在与两个.cc文件中,那么编译器对于这俩的初始化顺序是不确定的。
既然出现了因为不同编译单元中的静态变量初始化导致,那么就需要针对性的解决这个问题,通常有如下几个方案:
-
将所有的静态全局变量放在一个编译单元中(如果涉及到依赖的话,需要修改顺序)。
-
强制编译器在编译阶段进行初始化,通常有constexpr和constinit两种。
-
Initialization On First Use,即在使用时候,通过函数获取静态对象的方式进行初始化。
标签:初始化,变量,静态,C++,bss,编译,线程 From: https://www.cnblogs.com/love-9/p/18086072