是的,在 x86 上有几个可能的选择。
XADD r/m, r
该指令以原子方式将第二个操作数 (r) 与第一个操作数 (r/m) 相加,并使用第一个操作数 (r/m) 的原始值加载第二个操作数 (r)。
要使用它,您需要加载带有增量的第二个操作数(我猜,这里是 1),第一个操作数应该是正在递增的内存位置。
该指令必须以 LOCK 前缀开头(它将使其成为原子指令)。
Microsoft Visual C++ 中的InterlockedAdd()
函数执行此操作,AFAIR 使用XADD
它是否可用(自 i80486 起可用)。
另一种方法是使用带有CMPXCHG
指令的循环......
伪代码:
while (true)
{
int oldValue = l.n;
int newValue = oldValue + 1;
if (CAS(&l.n, newValue, oldValue) == oldValue)
break;
}
CAS()
代表(并发编程中的Compare And Swap
一个常用术语)是一个尝试用新值原子地替换内存中的值的函数。当被替换的值等于最后提供的参数时,替换成功oldValue
。否则它会失败。CAS
从内存中返回原始值,这让我们知道替换是否成功(我们将返回的值与 进行比较oldValue
)。失败(返回的原始值与 不同oldValue
)表明在读取oldValue
和我们尝试用newValue
另一个线程替换它的那一刻改变了内存中的值。在这种情况下,我们只需重试整个过程。
CMPXCHG
指令是CAS
x86 。
在 Microsoft Visual C++中InterlockedCompareExchange()
使用CMPXCHG
来实现CAS
.
如果XADD
不可用,InterlockedAdd()
则使用CAS
//实现CMPXCHG
。InterlockedCompareExchange()
在其他一些 CPU 上,可能还有其他可能性。有些允许原子执行一些相邻的指令。