c#自增/自减操作的线程安全性

本文关键字:线程 安全性 操作 自增 | 更新日期: 2023-09-27 18:17:29

我试图研究一段简单的代码,两个线程访问一个共享的整数变量,一个递增,另一个递减:

static int n = 0;
static void Main()
{
    var up = new Task(() =>
    {
        for (int j = 0; j < 400000; j++)
           ++n;
    });
    up.Start();
    for (int i = 0; i < 400000; i++)
        --n;
    up.Wait();
    Console.WriteLine(n);
    Console.ReadKey();
}

我读过很多次c#的自增/自减操作不是线程安全的,应该用互锁来代替。递增和递减方法。这确实有效,但是当我尝试设置断点并检查反汇编窗口时,它看起来好像++和——操作符是原子的,它们的汇编等效值是

inc dword ptr ds:[29A0C9Ch]

dec dword ptr ds:[29A0C9Ch]

。那么,为什么上面的代码有时输出一个非零值呢?

c#自增/自减操作的线程安全性

因为它们不是原子的:为什么x86的INC指令不是原子的?

Interlocked同步缓存,并确保没有中断发生。

为什么i++在单核机器上不是线程安全的?

有更多的细节

那么为什么上面的代码有时输出一个非零值呢?

因为incdec不是原子。处理器将这些转换成较低级别的指令(例如,inc => read + add + store)