不能通过并发线程访问破坏数据

Des*_*tar 2 .net c# multithreading locking

我写这个实验是为了向某人证明使用多个线程同时访问共享数据是一个很大的禁忌。令我惊讶的是,无论我创建了多少线程,我都无法创建并发问题,并且该值始终导致平衡值 0。我知道增量运算符不是线程安全的,这就是为什么有方法的原因喜欢Interlocked.Increment()Interlocked.Decrement()(这里也提到了 ++ 运算符线程安全吗?)。

如果递增/递减运算符不是线程安全的,那么为什么下面的代码执行没有任何问题并且结果达到预期值?

下面的代码段创建了 2,000 个线程。1,000 不断递增,1,000 不断递减,以确保多个线程同时访问数据。更糟糕的是,在普通程序中,您不会有那么多线程。然而,尽管为了造成并发问题而夸大了数字,但该值始终导致平衡值 0。

static void Main(string[] args)
    {
        Random random = new Random();
        int value = 0;

        for (int x=0; x<1000; x++)
        {
            Thread incThread = new Thread(() =>
            {
                for (int y=0; y<100; y++)
                {
                    Console.WriteLine("Incrementing");
                    value++;
                }
            });

            Thread decThread = new Thread(() =>
            {
                for (int z=0; z<100; z++)
                {
                    Console.WriteLine("Decrementing");
                    value--;
                }
            });

            incThread.Start();
            decThread.Start();
        }

        Thread.Sleep(TimeSpan.FromSeconds(15));
        Console.WriteLine(value);
        Console.ReadLine();
    }
Run Code Online (Sandbox Code Playgroud)

我希望有人能给我一个解释,让我知道我编写线程安全软件的所有努力都没有白费,或者这个实验在某些方面存在缺陷。我也尝试过所有线程递增并使用 ++i 而不是 i++。该值始终产生预期值。

Jon*_*eet 5

如果您有两个在非常接近的时间递增和递减的线程,您通常只会看到问题。(也有内存模型问题,但它们是分开的。)这意味着您希望它们花费大部分时间递增和递减,以便为您提供操作冲突的最佳机会。

目前,您的线程将花费绝大多数时间睡眠或写入控制台。这大大减少了碰撞的机会。

此外,我要指出,没有证据并不是没有证据 - 并发问题确实很难引起,特别是如果您碰巧在具有强大内存模型和内部原子递增/递减指令的 CPU 上运行JIT可以使用。可能是您永远不会在您的特定机器上引发问题 - 但相同的程序可能会在另一台机器上失败。