Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# thread safety of global configuration settings

In a C# app, suppose I have a single global class that contains some configuration items, like so :

public class Options  
{  
    int myConfigInt;  
    string myConfigString;  
    ..etc.  
}  

static Options GlobalOptions;  

the members of this class will be uses across different threads :

Thread1: GlobalOptions.myConfigString = blah;

while

Thread2: string thingie = GlobalOptions.myConfigString;

Using a lock for access to the GlobalOptions object would also unnecessary block when 2 threads are accessing different members, but on the other hand creating a sync-object for every member seems a bit over the top too.

Also, using a lock on the global options would make my code less nice I think; if I have to write

string stringiwanttouse;
lock(GlobalOptions)
{
   stringiwanttouse = GlobalOptions.myConfigString;
}

everywhere (and is this thread-safe or is stringiwanttouse now just a pointer to myConfigString ? Yeah, I'm new to C#....) instead of

string stringiwanttouse = GlobalOptions.myConfigString;

it makes the code look horrible.

So... What is the best (and simplest!) way to ensure thread-safety ?

like image 700
Led Avatar asked May 28 '09 19:05

Led


2 Answers

You could wrap the field in question (myConfigString in this case) in a Property, and have code in the Get/Set that uses either a Monitor.Lock or a Mutex. Then, accessing the property only locks that single field, and doesn't lock the whole class.

Edit: adding code

private static object obj = new object(); // only used for locking
public static string MyConfigString {
    get {
       lock(obj)
       {
          return myConfigstring;
       }
    }
    set {
       lock(obj)
       {
          myConfigstring = value;
       }
    }
}
like image 146
Mike Avatar answered Sep 30 '22 15:09

Mike


The following was written before the OP's edit:

public static class Options
{
    private static int _myConfigInt;
    private static string _myConfigString;

    private static bool _initialized = false;
    private static object _locker = new object();

    private static void InitializeIfNeeded()
    {
        if (!_initialized) {
            lock (_locker) {
                if (!_initialized) {
                    ReadConfiguration();
                    _initalized = true;
                }
            }
        }
    }

    private static void ReadConfiguration() { // ... }

    public static int MyConfigInt {
        get {
            InitializeIfNeeded();
            return _myConfigInt;
        }
    }

    public static string MyConfigString {
        get {
            InitializeIfNeeded();
            return _myConfigstring;
        }
    }
    //..etc. 
}

After that edit, I can say that you should do something like the above, and only set configuration in one place - the configuration class. That way, it will be the only class modifying the configuration at runtime, and only when a configuration option is to be retrieved.

like image 34
John Saunders Avatar answered Sep 30 '22 16:09

John Saunders