这是简单的代码,
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
上,所以有人能给我一些解释吗?感谢
答案 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
作为标识符,它是一个保留字。请改用AsyncWeird
,InnerClass
,HelloContainer
或任何非官方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变量。