如果负载是原子的,则在运行时检测?

时间:2015-03-23 23:18:03

标签: c++ c++11 atomic memory-fences

我的应用程序需要几个原子载荷和存储。不幸的是,这些操作必须发生在内存映射文件中的特定地址,所以我不能使用c ++ 11的std :: atomic(因为std :: atomic通过控制变量的大小和对齐/位置来工作)由于我控制了内存映射文件格式,我们只运行在一个单独的CPU架构上,我只是查看了目标的对齐和大小限制,并排列了允许原子性的东西(包括在正确位置的完整围栏)。

有没有办法测试(在运行时)特定大小的特定大小的读取或写入是否是原子的?我的主要平台是x86-64,但我也对ARM的解决方案感兴趣。

1 个答案:

答案 0 :(得分:1)

简短回答:可能不是。您可以编写一些代码来更新和检查您的值的有效性,并运行它6个月。但是,几乎肯定不能保证代码是正确的 - 只是你没有找到合适的位置使它出错。

长答案:处理器字的加载和存储几乎肯定是原子的,但是std::atomic功能提供了更强的保证。它保证没有处理器将使用“陈旧”的值(缓存一致性和独占更新)。如果没有std::atomic,你就无法做出同样的保证(除非平台本身保证这一点,这可能要求它至少是一个单核处理器)。

在一般情况下,由处理器执行的加载和存储具有“弱”高速缓存一致性和原子更新策略。假设我们有这个代码:

 int a = 42; 
 bool flag = false;

 ... 

 a++;
 flag = true;

和其他一些代码:

 while(!flag)
 a--;

[我当前忽略了flag也需要原子更新策略并且可能需要易变的事实 - 在这种情况下不是重点]

无法保证编译器不会形成tmp = a; tmp = tmp+1; a = tmp;(并且对应于a--)[可能会在其间抛出额外的指令以获得良好的度量,因为编译器希望更快/以其他方式更好]。

也无法保证该值不会更新为43,但其他代码在退出循环后已读取旧42值,因为flag为是的(因为处理器没有按照您期望的顺序执行所有操作,并且缓存内容会“无序”更新。)

x86处理器绝对是那些没有得到保证的保证,如上所述,更新的值将立即可用。缓存一致性和原子性只是保证你不会读取一些“半生不熟”的值 - 它在更新值时是“旧”值或“新”值 - 但它可能是相当长一段时间的“旧”值在写入“新”值之后,这通常是“不是一件好事”。