为什么在多线程环境中类实例值被破坏?

时间:2016-05-19 10:37:26

标签: c# multithreading

这是简单的代码,

class Program
{
    static void Main(string[] args)
    {
        for (int i = 0; i < 100; i++)
        {
            Thread thread = new Thread(new ThreadStart(()=> SimpleClass.Instance.weird.SetHello(i)));
            thread.Start();
        }

        Console.Read();
    }
}

interface IClass
{
    WeirdClass weird{ get; set; }
}

class SimpleClass : IClass {
    public static SimpleClass Instance = new SimpleClass();

    public WeirdClass weird{ get; set; }

    public SimpleClass()
    {
        weird= new WeirdClass();
    }
}

class WeirdClass
{
    public int hello;

    public void SetHello(int i)
    {
        this.hello = i;
        Console.WriteLine(this.hello);
    }
}

我们可以看到&#39;你好&#39; WeirdClass中的值在多线程中是不正确的,值就像一个静态实例,但它不是。

也许魔法发生在SimpleClass.Instance.async上,所以有人能给我一些解释吗?感谢

1 个答案:

答案 0 :(得分:0)

我提出了你的问题,因为它带来了一些有趣的研究。

在for循环中,将i变量赋值给临时ii并在线程初始化中使用ii,如下所示:

var ii = i;
Thread thread = new Thread(
    new ThreadStart(()=> SimpleClass.Instance.async.SetHello(ii)));
thread.Start();

我已使用不同的配置和不同的上下文对其进行了测试(例如,在Thread.Sleep作业和hello之间放置一个随机的Console.WriteLine

我的解决方案是这样的:每个线程都有自己独特的i,并在Console上一次写入。 但这些数字并不是按顺序编写的,因为线程在创建时不会按顺序开始

只是旁注:正如@JonSkeet建议的那样,不要使用async作为标识符,它是一个保留字。请改用AsyncWeirdInnerClassHelloContainer或任何非官方C#令牌,否则您的代码就会变得不那么清晰。

更新 - 解决方案:

此:

for(int i = 0; i < 10; i++)

相当于:

int i;
for(i = 0; i < 10; i++)

也就是说,在两种情况下i都是在for循环之外创建的,因此它在循环的不同循环之间以某种方式共享。如果您查看提供的@CodeCaster链接,您将看到与{C#的先前版本的foreach循环相同的问题。

如果你在一个以i作为输入的循环中声明线程,你就告诉线程:&#34;好的,当你开始时,得到i !值&#34; 。在那一刻,i具有正确的值,但线程仅在i有效启动时才询问i,因此该值已经更改,因为在此期间主线程已经开始循环的新循环,并已为下一次迭代重新分配ii

相反,如果你在循环中创建了一个临时变量ii ,那么它将保持在该循环中,并且无法在外面看到。

这是整个游戏的演示:尝试在循环外部声明i ...行为再次是错误的,你用{{1变量。