C#Static跨线程的变量访问

Rex*_*ten 7 c# multithreading

我在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
          }

      });
   }
}
Run Code Online (Sandbox Code Playgroud)

在使用某些类型的静态成员时,这是一个线程突变问题吗?

小智 7

使用volatile或替代使用Interlocked访问变量.

您遇到的问题是编译器(以及本机编译器)可以在没有它们的情况下自由地优化对他认为合适的变量的访问.所以他可能会将一个变量转储到寄存器中,而不是重新读取它.

为了避免它,您必须确保该变量实际上是真正读取的.挥发性就是这样.Interlocked也是如此(并允许增量/添加等以原子方式发生).

哪个更好你必须决定.两者都迫使处理器上的存储器屏障,当经常完成时,它确实具有非常重要的成本.我经常使用的一种模式是将这些对象主要读取,这样我只能替换根对象(一个内存屏障).手动处理内存障碍(可能,请阅读关键字的手册)是一件很难的事情.但是,效率要高得多 - 取决于你在那里做多少等等,可能需要它.