多个线程获得相同的值(值类型),但直到值更改后才创建线程

时间:2018-02-21 05:55:33

标签: c# multithreading

背景

我创建了一个“比赛”线程的简单程序。这还不完整,但它是学习新事物的试验台。

现在,我正在“学习如何创建线程”阶段。

程序如下:

class Program
{
    static void Main(string[] args)
    {
        for (int i = 0; i < 10, i++)
        {
            Thread racer = new Thread(() => GetRacer(i));
            racer.Start();
        {

        Console.ReadLine();
    }

    public static Racer GetRacer(int designation)
    {
        return new Racer(Convert.ToString(designation));
    }

}

public class Racer
{
    public Racer(string name)
    {
        Random myRand = new Random(1234);
        Thread.Sleep(myRand.Next(1000, 2000));
        Console.WriteLine(name);
    }
{

问题

我遇到的具体问题是多个Racers具有相同的名称,但i的值在创建新Racer之前发生了变化。为什么会这样?

2 个答案:

答案 0 :(得分:1)

答案在于来自@Sami的评论,您可以使用另一个本地变量来解决它。

class Program
{
    static void Main(string[] args)
    {
        for (int i = 0; i < 10; i++)
        {
            int copy = i;
            Thread racer = new Thread(() => GetRacer(copy));
            racer.Start();
        }
        Console.ReadLine();
    }

    public static Racer GetRacer(int designation)
    {
        return new Racer(Convert.ToString(designation));
    }
}

public class Racer
{
    public Racer(string name)
    {
        Random myRand = new Random(1234);
        Thread.Sleep(myRand.Next(1000, 2000));
        Console.WriteLine(name);
    }
}

在类似的帖子中可以找到更多解释。 Multithreading and closures in .NET

答案 1 :(得分:1)

在检查IL之后(这是我第一次这样做,我会承认),我发现问题在于Lambda的实现方式。作为免责声明,我不完全理解这里发生的事情,但我想我已经足够了解问题所在。

如果我们查看IL,我们可以看到编译器创建了一个名为<>c__displayclass0_0的新对象。这个类就是实现lambda的方式。

它创建一个字段.field public int32 i,它对应于lambda的输入,以及一个与lambda本身对应的方法。

Main方法只有<>c__displayclass0_0的一个实例。每当for循环更改i的值时,它也会更新<>c__displayclass0_0.field public int32 i的值。

然后创建并启动新线程,向其传递对<>c__displayclass0_0的一个实例的引用。然后,因为for循环的迭代完成,它再次启动for循环。因此,如果<>c__displayclass0_0.field public int32 i的值恰好在新线程获得执行时间之前发生更改,则将使用i的新值。

这有一个有趣的副作用,有时一个线程会显示值10,因为for循环在检查之前会增加i,看它是否低于10。