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单件。”) 所以上边提到的方案是一种保护局部静态对象防止竞争的非常好的解决方案。

《Imperfect C++》读书笔记

Imperfect C++   译序一 在本书中,Matthew Wilson不但为我们指出C++中诸多不完美之处,还提供了经过实践检验的应对技术和技巧,便于我们利用“不完美的C++”编写出近乎...
  • backard
  • backard
  • 2013年01月23日 20:06
  • 709

STATICS

STATICS Syntax STATICS stat [options]. Effect Declaration of static variables stat. The s...
  • zhongguomao
  • zhongguomao
  • 2012年07月04日 11:37
  • 1228

《Imperfect C++》译序[已出版]

                           《Imperfect C++》译序                                                      ...
  • hejishan
  • hejishan
  • 2008年04月01日 16:51
  • 142

c++11: thread_local

thread_local变量是C++ 11新引入的一种存储类型。它会影响变量的存储周期(Storage duration),C++中有4种存储周期: automatic static dynamic ...
  • woshi_caibi
  • woshi_caibi
  • 2017年05月03日 15:53
  • 979

从template到static

template static 访问权限
  • u011327981
  • u011327981
  • 2017年03月08日 15:17
  • 318

struts 中 Freemarker 调用 static 方法

http://autumnice.blog.163.com/blog/static/5552002011912102954555/ freemarker中调用java的静态方法或静态变量。...
  • iamfafa
  • iamfafa
  • 2015年03月16日 11:01
  • 1794

【Node.js-3】express介绍、express-static处理静态文件请求、链式操作next()、中间件、cookie、session

1、我们原生的创建服务,设置监听,处理请求之前已经写过。这里介绍的express可以理解是基于基础之上的一个框架,既然是框架,里面肯定封装了很多东西,我们用的时候会方便很多,到底方便在哪里,我们写个例...
  • wsb200514
  • wsb200514
  • 2017年08月06日 00:35
  • 586

廖雪峰Git教程笔记(十一)添加远程库

我们已经在本地创建了一个git仓库,又想在github创建一个git仓库,并且让这两个仓库远程同步,这样,git上的仓库既可以作为备份,又可以让其他人通过该仓库来协作。。。。 首先,登陆GitH...
  • abc15766228491
  • abc15766228491
  • 2018年01月18日 11:43
  • 35

mesh deformation资料

mesh deformation:是一个比较有意思的课题,除了最近流行的一些深度学习的方法,以前经典的方法概括起来就是解决:最优化某个可能有约束(等式或不等式约束,线性或非线性约束)的能量项。其重点在...
  • baidu_26408419
  • baidu_26408419
  • 2017年09月08日 16:14
  • 273

C#中,public,protected,private,static

每个类都创造了有自己的名字空间,指方法和变量可以知道彼此的存在,可以使用。 public类不但可以被同一程序包中的其它类使用,别的程序包中的类也可以使用; 变量和方法的修饰字public、protec...
  • yfgcq
  • yfgcq
  • 2010年01月22日 17:00
  • 3030
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Imperfect C++:Chapter 11 Statics:11.3Function-Local static objects
举报原因:
原因补充:

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