分享
 
 
 

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

王朝c/c++·作者佚名  2006-01-31
窄屏简体版  字體: |||超大  

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

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有