首页 > 解决方案 > 线程表现异常

问题描述

以下在 Windows 10 上运行的 .Net 5 多线程代码应该计算出_sum非确定性的值,例如 2,4 和 8。但是,_sum始终为 10,即正确答案。似乎已经应用了锁_sum

任何人都可以阐明这个问题吗?

using System;
using System.Threading;

namespace MtAdd
{
    class Program
    {
        private static int _sum = 0; //shared resource  
        
        static void Main(string[] args)
        {
            var threads = new Thread[10];

            //Add 1 to _sum for ten times. 
            for (var i = 0; i < threads.Length; i++)
            {
                threads[i] = new Thread(AddOne);
                threads[i].Start();
            }

            foreach (var t in threads)
            {
                t.Join();
            }
            
            Console.WriteLine("[{0}] sum = {1}", 
                              Thread.CurrentThread.ManagedThreadId, 
                              _sum);
        }

        private static void AddOne()
        {
            Console.WriteLine("[{0}] AddOne called", Thread.CurrentThread.ManagedThreadId);
            _sum++; //critical section
        }
    }
}
[4] AddOne called
[5] AddOne called
[7] AddOne called
[6] AddOne called
[8] AddOne called
[9] AddOne called
[10] AddOne called
[11] AddOne called
[12] AddOne called
[13] AddOne called
[1] sum = 10

标签: c#.netwindowsmultithreading

解决方案


Three things to increase the probability get a "wrong" answer:

  • get rid of Console.WriteLine: see @Hans explanation in comments

  • increase the concurrency: ie if 10 is not enough, try 1_000_000 threads

  • use Task.Run(AddOne): it will run AddOne in the thread pool. It costs very little runtime to start a thread from here because the CLR keeps a pool of already-started threads. Whereas new Thread(action).Start can take around 100ms to actually create a new thread.

The code below prints 982266 rather than 1000000 on my computer. Try on yours and let us know:

    var tasks = new Task[1_000_000];

    for (var i = 0; i < tasks.Length; i++)
        tasks[i] = Task.Run(AddOne);

    Task.WaitAll(tasks);

    Console.WriteLine(_sum);

推荐阅读