在运行时检测负载是否是原子的?
Detect at runtime if a load is atomic?
我的应用程序需要几个原子加载和存储。不幸的是,这些操作必须发生在内存映射文件中的特定地址,因此我不能使用 c++11 的 std::atomic(因为 std::atomic 通过控制变量的大小和 alignment/placement 来工作. 因为我控制了内存映射文件格式,而我们只在一个 CPU 架构上 运行在正确的位置围栏)。
有没有一种方法可以测试(在 运行 时间)对特定地址的特定大小的读取或写入是否是原子的?我的主要平台是 x86-64,但我也对 ARM 的解决方案感兴趣。
简短回答:可能不会。您可以编写一些代码来更新和检查您的值的有效性,并且 运行 持续 6 个月。然而,它几乎肯定不能保证代码是正确的——只是你没有找到正确的地方让它出错。
长答案:处理器字的加载和存储本身几乎肯定是原子的,但是 std::atomic
功能提供了比这更强的保证。它保证没有处理器会使用 "stale" 的值(缓存一致性和独占更新)。没有 std::atomic
就无法做出相同的保证(除非平台本身保证这一点,这可能要求它至少是一个单核处理器)。
在一般情况下,处理器执行的加载和存储具有 "weak" 缓存一致性和原子更新策略。假设我们有这个代码:
int a = 42;
bool flag = false;
...
a++;
flag = true;
和其他一些代码:
while(!flag)
a--;
[我目前忽略了一个事实,即 flag
也需要原子更新策略并且可能需要是易变的——这不是本例的重点]
不能保证编译器不会形成 tmp = a; tmp = tmp+1; a = tmp;
(和 a--
对应)[可能为了更好的衡量而在两者之间插入额外的指令,因为编译器希望它以其他方式faster/better]。
也不能保证该值不会更新为43
,但其他代码在退出循环后读取了旧的42
值,因为flag
是真的(因为处理器没有完全按照您期望的顺序执行所有操作,并且缓存内容已更新 "out of order")。
x86 处理器肯定是那些没有得到更新值将立即可用的保证的处理器之一,如上所述。缓存一致性和原子性只是保证您不会读取某些 "half-baked" 值 - 在更新值时它可能是 "old" 或 "new" 值 - 但它可能是 "old" 值在写入 "new" 值后的相当长一段时间内,通常为 "not a good thing".
我的应用程序需要几个原子加载和存储。不幸的是,这些操作必须发生在内存映射文件中的特定地址,因此我不能使用 c++11 的 std::atomic(因为 std::atomic 通过控制变量的大小和 alignment/placement 来工作. 因为我控制了内存映射文件格式,而我们只在一个 CPU 架构上 运行在正确的位置围栏)。
有没有一种方法可以测试(在 运行 时间)对特定地址的特定大小的读取或写入是否是原子的?我的主要平台是 x86-64,但我也对 ARM 的解决方案感兴趣。
简短回答:可能不会。您可以编写一些代码来更新和检查您的值的有效性,并且 运行 持续 6 个月。然而,它几乎肯定不能保证代码是正确的——只是你没有找到正确的地方让它出错。
长答案:处理器字的加载和存储本身几乎肯定是原子的,但是 std::atomic
功能提供了比这更强的保证。它保证没有处理器会使用 "stale" 的值(缓存一致性和独占更新)。没有 std::atomic
就无法做出相同的保证(除非平台本身保证这一点,这可能要求它至少是一个单核处理器)。
在一般情况下,处理器执行的加载和存储具有 "weak" 缓存一致性和原子更新策略。假设我们有这个代码:
int a = 42;
bool flag = false;
...
a++;
flag = true;
和其他一些代码:
while(!flag)
a--;
[我目前忽略了一个事实,即 flag
也需要原子更新策略并且可能需要是易变的——这不是本例的重点]
不能保证编译器不会形成 tmp = a; tmp = tmp+1; a = tmp;
(和 a--
对应)[可能为了更好的衡量而在两者之间插入额外的指令,因为编译器希望它以其他方式faster/better]。
也不能保证该值不会更新为43
,但其他代码在退出循环后读取了旧的42
值,因为flag
是真的(因为处理器没有完全按照您期望的顺序执行所有操作,并且缓存内容已更新 "out of order")。
x86 处理器肯定是那些没有得到更新值将立即可用的保证的处理器之一,如上所述。缓存一致性和原子性只是保证您不会读取某些 "half-baked" 值 - 在更新值时它可能是 "old" 或 "new" 值 - 但它可能是 "old" 值在写入 "new" 值后的相当长一段时间内,通常为 "not a good thing".