博客
关于我
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/

    你可能感兴趣的文章
    Oracle收购DataScience.com扩展云平台分析能力
    查看>>
    Oracle教程之管理索引(七)--Oracle显示索引信息
    查看>>
    oracle数据库 添加定时器
    查看>>
    Oracle数据库DBA日常Sql列表
    查看>>
    Oracle数据库ORA-01555解决含clob和blob字段表报错快照过旧问题
    查看>>
    ubuntu24 finalshell 无法连接ubuntu服务器, 客户端无法连接ubuntu, 无法远程连接ubuntu。
    查看>>
    Oracle数据库入门——初级系列教程
    查看>>
    oracle数据库包package小例子
    查看>>
    UBUNTU 添加删除用户
    查看>>
    Oracle数据库备份与还原
    查看>>
    Ubuntu Seata开机自启动服务
    查看>>
    uart 驱动架构
    查看>>
    Oracle数据库学习(三)
    查看>>
    Oracle数据库安装成功后,忘记解锁账户和设置密码
    查看>>
    TypeError: create_purple() 接受 0 个位置参数,但给出了 2 个
    查看>>
    Oracle数据库异常--- oracle_10g_登录em后,提示java.lang.Exception_Exception_in_sending_Request__null或Connection
    查看>>
    Oracle数据库异常---OracleDBConsoleorcl无法启动
    查看>>
    oracle数据库异常---SP2-1503: 无法初始化 Oracle 调用界面 SP2-1503: 无法初始化 Oracle 问题的解决办法
    查看>>
    Oracle数据库性能调优
    查看>>