是的,在 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指令是CASx86 。
在 Microsoft Visual C++中InterlockedCompareExchange()使用CMPXCHG来实现CAS.
如果XADD不可用,InterlockedAdd()则使用CAS//实现CMPXCHG。InterlockedCompareExchange()
在其他一些 CPU 上,可能还有其他可能性。有些允许原子执行一些相邻的指令。