首页 > 解决方案 > 输出的时候发现currentId不是预期的10000。为什么?如何纠正它

问题描述

我偶然看到的这段代码。代码大致如下。

    public class Question2
    {
        public void Run()
        {
            List<Task> tasks = new List<Task>();
            for (int i = 0; i < 10000; i++)
            {
                tasks.Add(Task.Factory.StartNew(() =>
                {
                    GetNextId();
                }));
            }
            Task.WaitAll(tasks.ToArray());
            
            Console.WriteLine("currentId=" + GetCurrentId());
            Console.ReadKey();
        }

        private int currentId;
        public int GetNextId()
        {
            currentId++;
            return currentId;
        }

        public int GetCurrentId()
        {
            return currentId;
        }
    }

我不知道为什么结果不是10000?有人可以告诉我为什么以及如何纠正它。

标签: c#multithreadingthread-safety

解决方案


您刚刚发现了线程安全的主题!currentId++翻译成

  1. 从内存中读取 currentId 的值
  2. 将此值加一
  3. 将此新值写回内存

现在想象你的循环只持续到 i < 3。第一个线程在第 1 步并读取值 0。在进入第 2 步之前,第二个线程在第 1 步,也读取 0。现在两个线程都进入第 2 步3、将两个1都写入内存。现在第三个线程启动,将从内存中读取 1,将其增加到 2 并将其写入内存。现在你有 2 而不是期望值 3。

要解决此问题,您可以使用Interlocked.Increment

    private int currentId;
    public int GetNextId()
    {
        return Interlocked.Increment(ref currentId);          
    }

但请注意,根据您的用例,当您使用GetNextId().


推荐阅读