为什么 memory_order_relaxed 在 x86 上使用原子(锁定前缀)指令? [英] Why does memory_order_relaxed use atomic (lock-prefixed) instructions on x86?

查看:56
本文介绍了为什么 memory_order_relaxed 在 x86 上使用原子(锁定前缀)指令?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 Visual C++ 2013 上,当我编译以下代码时

On Visual C++ 2013, when I compile the following code

#include <atomic>

int main()
{
    std::atomic<int> v(2);
    return v.fetch_add(1, std::memory_order_relaxed);
}

我在 x86 上得到以下程序集:

I get back the following assembly on x86:

51               push        ecx  
B8 02 00 00 00   mov         eax,2 
8D 0C 24         lea         ecx,[esp] 
87 01            xchg        eax,dword ptr [ecx] 
B8 01 00 00 00   mov         eax,1 
F0 0F C1 01      lock xadd   dword ptr [ecx],eax 
59               pop         ecx  
C3               ret              

在 x64 上类似:

B8 02 00 00 00    mov         eax,2 
87 44 24 08       xchg        eax,dword ptr [rsp+8] 
B8 01 00 00 00    mov         eax,1 
F0 0F C1 44 24 08 lock xadd   dword ptr [rsp+8],eax 
C3                ret              

我就是不明白:为什么int变量的relaxed增量需要lock前缀?

I simply don't understand: why does a relaxed increment of an int variable require a lock prefix?

这是有原因的,还是他们根本不包括删除它的优化?

Is there a reason for this, or did they simply not include the optimization of removing it?

* 我使用 /O2/NoDefaultLib 来修剪它并去掉不必要的 C 运行时代码,但这与问题无关.上>

* I used /O2 with /NoDefaultLib to trim it down and get rid of unnecessary C runtime code, but that's irrelevant to the question.

推荐答案

因为原子性仍然需要锁;即使使用 memory_order_relaxed,递增/递减的要求也太严格而不能无锁.

Because a lock is still required for it to be atomic; even with memory_order_relaxed the requirement for increment/decrement is too strict to be lockless.

想象一下没有锁的情况.

Imagine the same thing with no locks.

v = 0;

然后我们生成 100 个线程,每个线程都使用以下命令:

And then we spawn 100 threads, each with this command:

v++;

然后您等待所有线程完成,您希望 v 是什么?不幸的是,它可能不是 100.假设值 v=23 是由一个线程加载的,并且在创建 24 之前,另一个线程也加载了 23,然后也写出了 24.所以线程实际上相互否定.这是因为增量本身不是原子的.当然,加载、存储、添加本身可能是原子的,但递增是多个步骤,所以它不是原子的.

And then you wait for all threads to finish, what would you expect v to be? Unfortunately, it may not be 100. Say the value v=23 is loaded by one thread, and before 24 is created, another thread also loads 23 and then writes out 24 too. So the threads actually negate each other. This is because the increment itself is not atomic. Sure, load, store, add may be atomic on their own, but incrementing is multiple steps so it is not atomic.

但是对于 std::atomic,无论 std::memory_order 设置如何,所有操作都是原子的.唯一的问题是它们将按什么顺序发生.memory_order_relaxed 仍然保证原子性,它只是可能在它附近发生的任何其他事情方面都是乱序的,即使对相同的值进行操作.

But with std::atomic, all operations are atomic, regardless of the std::memory_order setting. The only question is what order they will happen in. memory_order_relaxed still guarantees atomicity, it just might be out of order with respect to anything else happening near it, even operating on the same value.

这篇关于为什么 memory_order_relaxed 在 x86 上使用原子(锁定前缀)指令?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆