为什么 memory_order_relaxed 在 x86 上使用原子(锁定前缀)指令? [英] Why does memory_order_relaxed use atomic (lock-prefixed) instructions on 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屋!