博客
关于我
C/C++编程教训----函数内静态类对象初始化非线程安全(C++11之前)
阅读量:637 次
发布时间:2019-03-14

本文共 1231 字,大约阅读时间需要 4 分钟。

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

背景

在日常开发中,许多程序员会在函数内使用静态变量,这样可以在函数内持久地记录某些信息,同时确保变量只能在函数内使用。不过,函数内静态的类对象初始化却存在一个线程安全问题,这个问题在我们的项目中导致了log4cxx封装接口的调用失败。

问题分析

我们的项目封装了log4cxx的接口,调用了getWarn这个函数。由于getWarn函数内部使用了静态变量来初始化一个Level对象,导致程序在多线程环境下Crash。

为了深入分析这个问题,博主制作了一个简单例子,研究这个静态变量为何在多线程环境下不安全。这个例子用了一个TestObject类,通过TestFunction函数返回一个静态TestObject对象。

例子

class TestObject {public:    int m_iVal;    TestObject() {        m_iVal = 4;    }};TestObject TestFunction() {    static TestObject obj;    return obj;}

这个代码在TestFunction函数中定义了一个静态对象obj,这个对象在TestFunction第一次被调用时会初始化,之后每次调用都会返回同一个obj。

线程安全问题

  • 初始化顺序:obj的构造函数只有在TestFunction第一次被调用时才会被调用,这意味着在多线程环境下,一个线程可能在另一个线程还未完成obj的初始化时,直接读取obj的成员变量,导致初始化的成员变量并没有被设置好。

  • 竞态条件:如果两个线程同时进入TestFunction,第一个线程在完成obj的初始化后,可能移动到了一个与第二个线程竞争的位置,导致第二个线程误认为obj已经被初始化,而实际上obj还未完全构造好。

  • 通过反汇编码可以看出,编译器在静态变量的初始化过程中引入了一种机制,比如通过一个标志位判断对象是否已被初始化。如果对象已经被初始化,直接返回它;否则,才会真正地初始化它,并调用构造函数。如果有多个线程同时进入这个过程,可能会出现竞态条件,使得对象的初始化结果不确定。

    C++11 线程安全支持

    在C++11中,Visual Studio 2015引入了一种新的机制来确保静态对象的线程安全。你可能通过某些内置函数,比如 _Initialize_Thread_header_Init_thread_footer 来实现这一点。这些函数在编译时默认是启用的,可以通过编译选项 /Zc:threadSafeInit= 来禁用。

    总结

  • C++11前:尽量避免在函数内使用静态静态对象。
  • 条件允许时:将编译器升级到支持C++11的版本,比如Visual Studio 2015或更高,以利用内置的线程安全机制。
  • 这种优化不仅解决了静态变量的线程安全问题,还提升了代码的整体质量,使得代码更容易维护和扩展。

    转载地址:http://xygoz.baihongyu.com/

    你可能感兴趣的文章
    Openlayers实战:modifystart、modifyend互动示例
    查看>>
    Openlayers高级交互(10/20):绘制矩形,截取对应部分的地图并保存
    查看>>
    Openlayers高级交互(16/20):两个多边形的交集、差集、并集处理
    查看>>
    Openlayers高级交互(17/20):通过坐标显示多边形,计算出最大幅宽
    查看>>
    Openlayers高级交互(19/20): 地图上点击某处,列表中显示对应位置
    查看>>
    Openlayers高级交互(8/20):选取feature,平移feature
    查看>>
    openlayers:圆孔相机根据卫星经度、纬度、高度、半径比例推算绘制地面的拍摄的区域
    查看>>
    OpenLDAP(2.4.3x)服务器搭建及配置说明
    查看>>
    OpenLDAP编译安装及配置
    查看>>
    OpenMCU(一):STM32F407 FreeRTOS移植
    查看>>
    OpenMCU(三):STM32F103 FreeRTOS移植
    查看>>
    OpenMCU(二):GD32E23xx FreeRTOS移植
    查看>>
    OpenMetadata 命令执行漏洞复现(CVE-2024-28255)
    查看>>
    OpenMMLab | S4模型详解:应对长序列建模的有效方法
    查看>>
    OpenMMLab | 【全网首发】Llama 3 微调项目实践与教程(XTuner 版)
    查看>>
    OpenMMLab | 面向多样应用需求,书生·浦语2.5开源超轻量、高性能多种参数版本
    查看>>
    OpenMV入门教程(非常详细)从零基础入门到精通,看完这一篇就够了
    查看>>
    OpenObserve云原生可观测平台本地Docker部署与远程访问实战教程
    查看>>
    OpenPPL PPQ量化(4):计算图的切分和调度 源码剖析
    查看>>
    OpenPPL PPQ量化(5):执行引擎 源码剖析
    查看>>