0
public class MyConfigurationData
{
   public double[] Data1 { get; set; }
   public double[] Data2 { get; set; }
}
public class MyClass
{
   private static object SyncObject = new object();
   private static MyConfigurationData = null;
   private static MyClass()
   {
      lock(SyncObject)
      {
         //Initialize Configuration Data
         //This operation is bit slow as it needs to query the DB to retreive configuration data
      }
   }
   public static MyMethodWhichNeedsConfigurationData()
   {
      lock(SyncObject)
      {
          //Multilple threads can call this method
          //I lock only to an extent where I attempt to read the configuration data
      }
   }
}

在我的应用程序中,我只需要创建一次配置数据并多次使用它。换句话说,我写一次,读很多次。而且,我想确保在写操作完成之前不会发生读取。换句话说,我不想将 MyConfigurationData 读取为 NULL。

我所知道的是静态构造函数在 AppDomain 中只调用一次。但是,当我准备配置数据时,如果任何线程试图读取这些数据,我将如何确保同步有效?最后,我想提高我的读取操作的性能。

我可以以无锁的方式实现我的目标吗?

4

3 回答 3

4

来自MSDN

静态构造函数用于初始化任何静态数据,或执行只需要执行一次的特定操作。在创建第一个实例或引用任何静态成员之前自动调用它。

所以你不需要lock在你的代码中使用,它实际上是线程安全的。在引用之前调用您的静态构造函数MyMethodWhichNeedsConfigurationData

public class MyClass
{
   private static MyConfigurationData = null;
   private static MyClass()
   {
   }

   public static MyMethodWhichNeedsConfigurationData()
   {
   }
}
于 2012-09-11T07:00:35.270 回答
2

只要您只读取数据,它就应该是线程安全的。很少有数据结构在读取时不是线程安全的(明显的反例可能包括延迟加载)。请注意,静态构造函数由运行时自动同步,因此您无需担心运行“初始化配置数据”步骤的多个线程。

所以:只要没有任何东西改变数据,你就已经安全了。您还可以通过将数据隐藏在不可变接口后面来使其更难出错,即

public class ConfigurationData {
    // or some similar immutable API...
    public double GetData1(int index) { return data1[index]; }
    public double GetData2(int index) { return data2[index]; }

    private readonly double[] data1, data2;

    public ConfigurationData(double[] data1, double[] data2) {
        this.data1 = data1;
        this.data2 = data2;
    }
}

然后你不需要任何锁:

public class MyClass
{
   private static MyConfigurationData;
   private static MyClass()
   {
     //Initialize Configuration Data
       MyConfigurationData = ...
     //This operation is bit slow as it needs to query the DB to retreive configuration data
   }
   public static MyMethodWhichNeedsConfigurationData()
   {          //Multilple threads can call this method
      var config = MyConfigurationData;

   }
}

请注意,删除锁可以提高并行性;它不会改变原始单线程性能。

那就是说:我应该建议一般不要使用静态数据;它使测试变得非常困难,并且如果您的需求发生变化,那么执行多租户之类的事情就会变得很棘手。拥有单个配置实例可能更谨慎,但将其作为某种形式的context传递到系统中。不过,这两种方法都可以成功使用——这只是需要注意的事情。

于 2012-09-11T07:04:28.403 回答
1

我认为您应该使用单例模式并将配置初始化逻辑放在“GetInstance”方法中,该方法将返回您的类的实例。

这样,您就不需要任何读取锁定机制。

于 2012-09-11T07:02:01.823 回答