参考Hans Boehm在"原子操作"下的一篇(稍微过时)的论文.它提到,存储器模型(当时提议)不会阻止一个优化编译器从被组合成单个负载上相同的变量组合负载,或存储的序列.他的例子如下(更新为希望纠正当前语法):
特定
atomic<int> v;
Run Code Online (Sandbox Code Playgroud)
代码
while( v.load( memory_order_acquire ) ) { ... }
Run Code Online (Sandbox Code Playgroud)
可以优化为:
int a = v.load(memory_order_acquire);
while(a) { ... }
Run Code Online (Sandbox Code Playgroud)
他表示,显然这会很糟糕.现在我的问题是,由于论文有点陈旧,当前的C++ 0x内存模型是否会阻止这种类型的优化,还是技术上仍然允许?
我对标准的阅读似乎倾向于被禁止,但使用"获取"语义使其不那么清晰.例如,如果它是"seq_cst",则模型似乎保证加载必须参与访问的总排序,并且只加载一次值因此似乎违反排序(因为它破坏序列发生在关系之前).
对于获取,我将29.3.2解释为意味着不能进行这种优化,因为"获取"操作必须遵守任何"释放"操作.只做一次获取似乎无效.
所以我的问题是当前模型(在待定标准中)是否会禁止这种类型的优化?如果是,那么哪一部分特别禁止呢?如果没有,是否使用volatile原子解决问题?
而对于奖金,如果加载操作具有"放松"排序,那么优化是否允许?
C++0x 标准试图禁止这种优化。
相关的话来自29.3p13:
实现应该使原子存储在合理的时间内对原子加载可见。
如果执行加载的线程只发出一个加载指令,那么这就违反了,就好像它第一次错过了写入一样,它永远不会看到它。加载使用哪种内存顺序并不重要,对于 和 来说都是相同 memory_order_seq_cst的memory_order_relaxed。
但是,允许进行以下优化,除非循环中存在强制排序的内容:
while( v.load( memory_order_acquire ) ) {
for(unsigned __temp=0;__temp<100;++__temp) {
// original loop body goes here
}
}
Run Code Online (Sandbox Code Playgroud)
即,编译器可以生成任意频率地执行实际加载的代码,只要它仍然执行它们即可。memory_order_seq_cst除非循环中存在其他操作,否则甚至允许这样做memory_order_seq_cst,因为这相当于在其他线程的任何内存访问之间运行 100 次迭代。
顺便说一句,使用memory_order_acquire并不具有您所描述的效果 --- 不需要看到释放操作(除了上面引用的 29.3p13 之外),只是如果它确实看到释放操作,那么它会施加可见性约束在其他访问上。
| 归档时间: |
|
| 查看次数: |
347 次 |
| 最近记录: |