Imperfect C++:Chapter 11 Statics:11.3Function-Local static objects

原创 2005年05月23日 18:35:00

By Matthew Wilson

树人 译

11.3Function-Local(局部于函数)的静态对象

  在前两节中我们着眼于非局部静态对象。在这一节中,我们来看看定义在函数作用域中的局部静态对象,例如:

Local &GetLocal()

{

  static Local local;

  return local;

}

  非局部和局部静态对象之间的关键性差别是局部静态对象在需要时被创建,也就是说函数第一次被调用时。此后的调用只是简单地使用已经被创建的实例。当然我们需要某种机制来记录那个被创建的实例,这样一个实现就可以使用一个未见过的初始化标记。

  尽管标准没有指定标记初始化的机制,但暗示还是非常清楚的。Section (C++-98: 6.7;4)提到:“对象在控制流第一次通过它的声明时被初始化;如果初始化因为抛出异常而退出,初始化没有完成,所以在下一次控制流进入声明位置时,会再次尝试初始化。在对象初始化时,如果控制流再次进入声明(递归地),其行为是未定义的。”所以,私底下前面的函数看上去很像下边的:

Listing 11.10.

Local &GetLocal()

{

  static bool  __bLocalInitialized__  = false;

  static byte  __localBytes__[sizeof(Local)];

  if(!__bLocalInitialized__)

  {

      new(__localBytes__) Local();

      __bLocalInitialized__ = true;

  }

  return *reinterpret_cast<Local*>(__localBytes__);

}

  以上情形的问题在于,在多线程环境下会导致一个竞争条件。可能会有多个线程进入并发现__bLocalInitialized__false,接着同时构造local。这会导致一个泄漏或者使进程崩溃,但不论发生什么都不我们想要的。

  有人可能会天真地[10]认为对static声明使用volatile关键可能会有帮助。毕竟,C标准说了(C99-5.1.1.2.3;2)“存取一个volatile对象,更改一个对象,修改一个文件或调用任何一个包含这些操作中任何一个的函数都是有副作用的,也就是改变了执行环境的状态。在执行序列中被指定的某个被称为序列点的位置,在此前估算的所有副作用会全部完成,而且随后的估算不会发生副作用。(附录C中给出的序列点的内容的概要。C++标准对此也说了很多(C++-98:1.9;7)。

[10]这里说的是我自己。哈,亦苦亦甜的记忆

  唉,标准没有说到任何关于线程的事实也意味着我们不能依靠一个实现(编译器)来支持我们的假设。在实践中,volatile的使用与保证对象使用的线程安全性毫无关系。因此,虽然volatile对其它一些东西(Section12.5)偶尔还是有作用的,但volatile本质上是和硬件相关的一种机制。

Imperfection: Function-local static instances of classes with nontrivial constructors are not thread-safe.

11.3.1牺牲延迟计算(lazy-evaluation)

  消除这个风险的一种方法是使用Schwarz计数器来确保在进入多线程模式之前所有的局部静态对象都被初始化掉(警告:不要在任何全局对象构造函数种初始化线程,在Section11.1中提到的)。这是很有效的,但同时它否定了大多数让对象局部化的目的。此外,如果过早调用的话,某些包含了局部静态对象的函数很可能不能恰当地工作;我们可能又回到全局对象的问题上了。

11.3.2救苦救难的自旋互斥量

  局部于线程的对象所固有的竞争条件是非常重要的,所以它不容忽视。但是,它也很少见。我们可以利用这个稀有物种,并使用一种极酷的优雅的解决方案[11],它是基于自旋互斥量的,这些互斥量自身依赖于在第10章中被测过的原子操作。

[11]提示:每次我提到一种极酷的优雅解决方案时,你可以肯定它是我自认为是自己所发明的。

Local &GetLocal()

{

    static int              guard; // Will be zeroed at load time

    spin_mutex              smx(&guard); // Spin on "guard"

    lock_scope<spin_mutex>  lock(smx);   // Scope lock of "smx"

    static Local            local;

    return local;

}

  一切都能工作,那是因为静态的guard变量在进程的零初始化阶段被设定。非静态的spin_mutex对象smx操作guard,而且通过一种lock_scope模板的参数化方法来给自己加锁,非静态的也是一样。所以,测试那些看不见的对于local及其自身的初始化标记的唯一方法就是通过有效的自旋互斥量的防护机制进行防护。

  当然这是由代价的,但如Section10.3所见到的,除非在被防护的段周围有一个高度并行的争用或者被防护的段很长,否则自旋互斥量的代价是非常低的。因为被防护段由一个(看不见的初始化标记的)比较和(返回local的地址的)一个移动组成,所以段本身代价是很低的。And it is hard to conceive of any client code where several threads will be contending for the Local singleton with such frequency that the likelihood of them wasting cycles in the spin will be appreciable.(实在不知如何翻译才好,我的理解是“很难想象任何这样的代码,在其中多个线程以很高(Zzzzz)的频率争用Local单件。”) 所以上边提到的方案是一种保护局部静态对象防止竞争的非常好的解决方案。

Data Structures and Other Objects Using C++ (Chapter 1) 学习笔记二

Preconditions and Postconditions(先决条件和后置条件)     When you are using a function, you only need to thin...

Imperfect C++ 读书笔记(一):约束

一、编译期契约:约束 这里主要讲述编译期的强制,C++不直接支持约束,本节描述了常用的约束设计方法。 1.1 must_have_base约束 此约束保证两个类之间的继承关系,代码如下: temp...

C++ Primer Chapter 11 generic algorithm

#if 0 //chapter11 Exercise 11.1 #include #include #include #include using namespace std; int m...

读书笔记:C++ primer 5th edition--chapter11.关联容器

part1.概述 1.关联容器中的元素是按关键字来保存和访问的,顺序容器是按它们在容器中的位置来顺序保存访问的。 2.8个关联容器。不同之处有三:1)set/map 2)是否允许重复关键字 (mu...
  • lebula
  • lebula
  • 2016年10月10日 00:51
  • 203

Learning C++ by Creating Games With UE4(15.05.21)(Chapter 11-3)Monster

Chapter11-3   下面我们需要使用蓝图来制作怪物攻击的效果(蓝图这部分基础讲解我不再涉及)   首先我们需要找到控制这个怪物的动画,我这边是这个,为了防止我们破坏原有的动画系统,我们...

Introduce to algorithm-----pseudo code to C/C++ code (chapter 11)

散列表 散列表是实现字典操作的一种有效数据结构。散列查找在 实际的应用中性能很出色。 散列,即将数据按照某种方法分散排列。而将数据关键字映射到储存空间的这种方法称为散列函数(has...

Learning C++ by Creating Games With UE4(15.05.21)(Chapter 11-2)Monster

Chapter11-2   近战攻击   在字典中定义近战这个词是表示一群混乱的人。近战攻击就是在很近的范围内做出的行为。要做近战攻击这样一个效果,你首先需要一个近战攻击的动画,那么你需要在U...

C++ Primer Plus,Chapter11, excercise11.1

1.随机漫步位置写入文件 //vecor.h #include #ifndef VECTOR_H_ #define VECTOR_H_ namespace VECTOR { class V...

Learning C++ by Creating Games With UE4(15.05.20)(Chapter 11-1)Monster

Chapter11-1 怪物   我们这一章节需要在场景中添加一个岛屿的场景作为范例。玩家将可以在整个岛上漫游,同时他也会遇到一些敌人,NPC可以在他遇到敌人之前给予他一定帮助和建议   岛屿...

《Imperfect C++》读书笔记

Imperfect C++   译序一 在本书中,Matthew Wilson不但为我们指出C++中诸多不完美之处,还提供了经过实践检验的应对技术和技巧,便于我们利用“不完美的C++”编写出近乎...
  • backard
  • backard
  • 2013年01月23日 20:06
  • 630
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Imperfect C++:Chapter 11 Statics:11.3Function-Local static objects
举报原因:
原因补充:

(最多只允许输入30个字)