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