首页 > 编程语言 >C++ 静态变量的初始化线程安全问题

C++ 静态变量的初始化线程安全问题

时间:2024-03-20 21:00:26浏览次数:17  
标签:初始化 变量 静态 C++ bss 编译 线程

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文件中,那么编译器对于这俩的初始化顺序是不确定的。

既然出现了因为不同编译单元中的静态变量初始化导致,那么就需要针对性的解决这个问题,通常有如下几个方案:

  • 将所有的静态全局变量放在一个编译单元中(如果涉及到依赖的话,需要修改顺序)。

  • 强制编译器在编译阶段进行初始化,通常有constexprconstinit两种。

  • Initialization On First Use,即在使用时候,通过函数获取静态对象的方式进行初始化。

 

标签:初始化,变量,静态,C++,bss,编译,线程
From: https://www.cnblogs.com/love-9/p/18086072

相关文章

  • 复试C++15真题_程序设计2_递归_输入字符串倒序转整形
    编写一个递归函数,功能为:输入一个字符串,输出一个整数值。例如输入 "1a2xcz34,5a!6" , 输出654321。一开始想不明白怎么写递归,于是我写了迭代的函数。意识到,递归的过程就是实现了迭代的循环,而循环内的操作本质没有太大差别。于是就写出来了:#include<iostream>usingnam......
  • C++ 引用底层解析
    1.引用的底层原理解析引用被称为变量的别名,它不能脱离被引用对象独立存在,这是在高级语言层面的概念和理解,并未揭示引用的实现方式。常见错误说法是“引用“自身不是一个变量,甚至编译器可以不为引用分配空间。引用地址空间存放的是被引用对象的地址。实际上,引用本身是一个变量,......
  • C++ extern
    extern有两个作用:当它与”C”一起连用时,如:extern“C”voidfun(inta,intb);则告诉编译器在编译fun这个函数名时按着C的规则去翻译相应的函数名而不是C++的。C++语言在编译的时候为了解决函数的多态问题,会将函数名和参数联合起来生成一个中间的函数名称,而C语言则不会,因......
  • 线程的种类-内核支持线程以及用户级线程
    内核支持线程:KST,在OS中的所有进程,无论是系统进程还是用户进程,都是在OS内核的支持下运行的,是与内核紧密相关的。而内核支持线程KST,也是在内核的支持下运行,他们的创建阻塞撤销和切换等都是在内核空间实现的。优点有:内核可同时调度进程中的多个线程并发运行;如果进程中的一个线程......
  • 线程的创建与终止
    线程的创建与终止:1.线程的创建:应用程序在启动时,通常仅有一个线程在执行,称为“初始化线程”,它的主要功能是创建新线程,利用一个线程创建函数,并提供相应参数,创建函数执行完毕后,返回一个线程标识符供以后使用。2.线程的终止:当一个线程完成了自己的任务后,或是线程在运行中出现异......
  • C++初阶:初识模板
        在之前的C与C++编程中,针对实现同样类型功能的函数我们学会使用了函数重载,终于可以不用记忆多个功能相同但是函数名不同的函数了喵。但是在实现的时候仍然显得有点不太方便,有些冗余。世界是懒人的世界,为了方便懒人的使用,模板应运而生~目录一、引子二、函数模......
  • 复试C++14真题 看程序写结果5 虚函数、继承 易错?
    复试C++14真题 看程序写结果5  虚函数、继承#include<iostream>usingnamespacestd;classA{public:virtualvoidprint(){cout<<"A::print"<<endl;}//voidprint(){cout<<"A::print"<<endl;}};classB:public......
  • (C++20) jthread中stop_token的基础使用
    (C++20)jthread中stop_token的基础使用文章目录(C++20)jthread中stop_token的基础使用C++20jthread使用方式循环判断条件变量condition_variable_anystop回调std::stop_callbackENDC++20jthreadstd::jthread-cppreference.comstd::stop_token-cpprefere......
  • c++简介
    C++(cplusplus)是一种计算机高级程序设计语言,由C语言扩展升级而产生[17],最早于1979年由本贾尼·斯特劳斯特卢普在AT&T贝尔工作室研发。C++既可以进行C语言的过程化程序设计,又可以进行以抽象数据类型为特点的基于对象的程序设计,还可以进行以继承和多态为特点的面向对象的......
  • Jmeter 之跨线程组传参(环境变量设置为全局变量)
    工作中往往会出现同一个测试计划下这个线程组下变量在另外一个线程组中使用,这就意味着需要把环境变量修改为全局变量 1.首先通过json提取器或者正则表达式的方式把数据提取出来 2.打开函数助手,选择setProperty函数, 生成函数${__setProperty(token,${access_token},)}3.......