C# 为什么类实例值在多线程环境中损坏?
下面是简单的代码C# 为什么类实例值在多线程环境中损坏?,c#,multithreading,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();
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);
}
}
类程序
{
静态void Main(字符串[]参数)
{
对于(int i=0;i<100;i++)
{
Thread-Thread=new-Thread(new-ThreadStart(()=>SimpleClass.Instance.wird.SetHello(i));
thread.Start();
}
Console.Read();
}
}
接口类
{
古怪类古怪{get;set;}
}
类SimpleClass:IClass{
公共静态SimpleClass实例=新SimpleClass();
公共古怪类古怪{get;set;}
公共SimpleClass()
{
怪异=新的古怪类();
}
}
阶级怪人阶级
{
公共int你好;
公共void SetHello(int i)
{
this.hello=i;
Console.WriteLine(this.hello);
}
}
我们可以看到,WeirdClass中的“hello”值在多线程中是不正确的,该值就像一个静态实例,但事实并非如此
也许魔法发生在
SimpleClass.Instance.async
上,有人能给我解释一下吗?谢谢我对你的问题投了赞成票,因为它给我带来了一些有趣的研究
在for循环中,将i
变量分配给tempii
并在线程初始化中使用ii
,如下所示:
var ii = i;
Thread thread = new Thread(
new ThreadStart(()=> SimpleClass.Instance.async.SetHello(ii)));
thread.Start();
我用不同的配置和不同的上下文对它进行了测试(例如,在hello
分配和Console.WriteLine
之间放置一个随机Thread.Sleep
)
我的解决方案是这样的:每个线程都有自己独特的i
,并将其一次性写入控制台。
但是这些数字不是按顺序写的,因为创建线程时线程不会按顺序开始
只是附带说明:正如@JonSkeet所建议的,不要使用async
作为标识符,它是一个保留字。请改用asyncywird
、InnerClass
、HelloContainer
,或者任何不是官方C#标记的东西,否则代码就会变得不那么清晰
更新-解决方案:
这:
for(int i=0;i<10;i++)
相当于:
int i;
for(i = 0; i < 10; i++)
inti;
对于(i=0;i<10;i++)
也就是说,在这两种情况下,i
都是在for
循环之外创建的,因此它以某种方式在循环的不同循环之间共享。如果您检查提供的@CodeCaster链接,您将看到以前版本的C#的foreach
循环存在相同的问题
如果以i
作为输入在循环中声明线程,则告诉线程:“好,开始时,获取i
值!”。此时,i
具有适当的值,但线程只有在有效启动时才会请求i
,因此该值已经更改,因为在此期间,主线程已经开始了新的循环周期,并且已经为下一次迭代重新分配了i
相反,如果在循环内部创建一个临时变量ii
,它将保持在该循环中,并且在外部看不到
这是整个游戏的演示:尝试在循环之外声明ii
。。。该行为同样是不正确的,您使用i
变量显示了该行为。请阅读并明确说明。它是如何“腐败”的?你知道你正在使用一个WeirdClass
实例吗?我还强烈建议不要使用async
作为标识符,因为它是一个上下文关键字…无论如何,你正在访问一个闭包,请看。是的,你的代码给了我正确的结果。。。。区别是什么……如果你想发布一个有用且正确的答案,你必须阅读。@MK87:新版本的C#编译器改变了这种行为。请注意,它由用于构建项目的.NET编译器版本决定,而不是运行时兼容性问题。
int i;
for(i = 0; i < 10; i++)