我在C#多线程程序中遇到了不良行为。我的一些静态成员在其他线程中丢失了它们的值,而一些相同的声明类型的静态不会丢失它们的值。
public class Context {
public Int32 ID { get; set; }
public String Name { get; set; }
public Context(Int32 NewID, String NewName){
this.ID = NewID;
this.Name = NewName;
}
}
public class Root {
public static Context MyContext;
public static Processor MyProcessor;
public Root(){
Root.MyContext = new Context(1,"Hal");
if(Root.MyContext.ID == null || Root.MyContext.ID != 1){
throw new Exception("Its bogus!") // Never gets thrown
}
if(Root.MyContext.Name == null || Root.MyContext.Name != "Hal"){
throw new Exception("It's VERY Bogus!"); // Never gets thrown
}
Root.MyProcessor = new MyProcessor();
Root.MyProcessor.Start();
}
}
public class Processor {
public Processor() {
}
public void Start(){
Thread T= new Thread (()=> {
if(Root.MyContext.Name == null || Root.MyContext.Name != "Hal"){
throw new Exception("Ive lost my value!"); // Never gets Thrown
}
if(Root.MyContext.ID == null){
throw new Exception("Ive lost my value!"); // Always gets thrown
}
});
}
}
在使用某些类型的静态成员时,这是一个线程突变问题吗?
答案 0 :(得分:7)
使用volatile
或使用Interlocked访问变量。
您遇到的问题是编译器(以及本机编译器)可以在没有它们的情况下自由地优化对他认为合适的变量的访问。所以他可能会将一个变量转储到一个寄存器中,而不是重读它。
为了避免它,您必须确保该变量实际上是真正读取的。挥发性就是这样。 Interlocked也是如此(并允许增量/添加等以原子方式发生)。
你必须决定哪个更好。两者都迫使处理器上的存储器屏障,当经常完成时,它确实具有非常重要的成本。我经常使用的一种模式是将这些对象主要读取,这样我只能替换根对象(一个内存屏障)。手动处理内存障碍(可能,请阅读关键字的手册)是一件很难的事情。但是,它的效率要高得多 - 取决于你在那里做多少等等。可能需要它。
答案 1 :(得分:3)
尝试对从多个线程修改/访问的变量使用volatile
修饰符
答案 2 :(得分:1)
多线程应用程序中的共享变量值是不确定的!您应该对每个共享资源使用锁定以避免逻辑中的冲突:
static Readonly Object _lock=new Object();
lock(_lock)
{
//accessing your shared variable
}