为什么这个多线程程序的输出会有所不同,除非使用 Thread.Join 或删除 Thread.Sleep?

问题描述 投票:0回答:1

我有以下程序,我生成 1000 个线程来递增共享变量 a,然后让每个线程休眠 1 秒:

using System;
using System.Diagnostics;
using System.Diagnostics.Metrics;
using System.Runtime.CompilerServices;
using System.Threading;

class Program
{

    static volatile int a = 0;
    static void Main()
    {
        List<Thread> threads = new List<Thread>();
        for (int i = 0; i < 1000; i++)
        {
            var t = new Thread(() =>
            {
                a++;
                Thread.Sleep(1000);
            });
            t.Start();
            threads.Add(t);
        }
        // foreach(Thread t in threads) t.Join();
        Thread.Sleep(60000);
        Console.WriteLine(a);
        Console.ReadKey();
    }
}

问题:

当我运行包含 Thread.Sleep(1000) 行并注释掉 t.Join() 的代码时,Console.WriteLine(a) 的输出小于 1000,即使我允许线程完成 60 秒.

如果我取消注释 t.Join() 循环或注释掉 Thread.Sleep(1000) 行,则输出始终为 1000。

问题:

当存在 Thread.Sleep(1000) 且 t.Join() 被注释掉时,为什么输出会有所不同?

为什么使用 t.Join() 或删除 Thread.Sleep(1000) 时输出会变得一致(始终为 1000)?

我希望能从线程行为和同步方面解释这里发生的事情。谢谢!

c# multithreading
1个回答
0
投票

TBH 无法重现

foreach(Thread t in threads) t.Join();
Thread.Sleep
效果 - 两者始终(在相对较少的尝试次数下)给出预期总和。我建议将代码更改为:

var t = new Thread(() =>
{
    Thread.Sleep(1000);   
    a++;
});

即改变操作顺序,那么

foreach(Thread t in threads) t.Join();
技巧将停止工作。事实上这只是一个巧合,我猜想与
a++
是相对较快的操作这一事实有关,并且由于您在将线程添加到列表并创建下一个线程之前启动线程,因此它有足够的时间来完成。更改睡眠和增量顺序将主要问题带到前面 -
a++
不是原子的,您应该使用一些同步,例如
Interlocked.Increment

© www.soinside.com 2019 - 2024. All rights reserved.