سؤال

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

In my application I need to create the configuration data only once and use it several multiple times. In other words, I write once and read many times. And also, I wanted to ensure that read should not happen till write operation is finished. In other words, I don't want to read MyConfigurationData as NULL.

What I know is the static constructor is called only once in an AppDomain. But, while I am preparing the configuration data, if any thread tries to read this data how would I ensure synchronization effectivey? In the end, I wanted to improve the performance of my read operation.

Can I implement my objective in a lock-free manner?

هل كانت مفيدة؟

المحلول

As long as you are only ever reading the data, it should already be thread-safe. Very few data-structures are not thread-safe when just reading (the obvious counter-examples might include lazy loading). Note that the static constructor is automatically synchronized by the runtime, so you don't need to concern yourself with multiple threads running the "Initialize Configuration Data" step.

So: as long as nothing ever mutates the data, you are already safe. You could also make it harder to get wrong by hiding the data behind an immutable interface, i.e.

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;
    }
}

Then you don't need any locks:

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;

   }
}

Note that removing the locks improves parallelism; it doesn't change raw single-threaded performance.

That said: I should advise against static data generally; it makes it very hard to test, and makes it tricky to do things like multi-tenancy if your needs change. It may be more prudent to have a single configuration instance, but pass it into the system as some form of context. Either approach can be used successfully, though - this is just something to be aware of.

نصائح أخرى

From MSDN:

A static constructor is used to initialize any static data, or to perform a particular action that needs performed once only. It is called automatically before the first instance is created or any static members are referenced.

So you don't need to use lock in your code, it is actually thread-safe. Your static constructor is called before MyMethodWhichNeedsConfigurationData is referenced.

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

   public static MyMethodWhichNeedsConfigurationData()
   {
   }
}

I think you should use Singleton pattern and put your configuration initialization logic in "GetInstance" method which would return the instance of your class.

This way you would not need any locking mechanism for Read.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top