views:

966

answers:

4

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 ?

+3  A: 

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;
       }
    }
}
Mike
+1 Also, you don't need to lock on ints or any object which guarantees atomic operations (i.e., thread safety).
Ed Swangren
nice catch! thx Ed.
Mike
Ed that is a dangerous statement. http://thith.blogspot.com/2005/11/c-interlocked.html
dss539
Sorry, I'm new to C#, so suppose I'd wrap it in a property with a get- and set accessor,how do I make the get thread-safe ?
Led
A: 
Harper Shelby
in this case it's mostly about a string specifying a download-directory that can be changed by the user at any time.I think the Observer-pattern might be overkill for just 1 or 2 global strings ?
Led
To elaborate, this is not production-code. I know about the ethics of programming ;)This is just a small hobby-project tool for my own use.
Led
+1  A: 

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.

John Saunders
I don't think he is trying to synchronize access to his config file, which is what it looks like you've given. Also, you have provided readonly access.
dss539
I deliberately made the access read-only. It's a configuration class. The only thing modifying the configuration should be the class.
John Saunders
My mistake, sorry John, after rereading my question I found it to be too vague indeed so I tried to elaborate a bit..
Led
Also, since you're new to C#, you should look up the use of the various classes in the System.Configuration namespace. In particular, if you're using Windows Forms (which you didn't say), then a Settings file is just right for you, as it allows per-user settings to be saved per-user, while keeping application-wide settings in one place. It's also dead easy to use. Right-click your project, choose "Properties", and click the "Settings" tab, and follow the instructions.
John Saunders
Thanks again John, good advice ! I'll look into it !
Led
A: 

What do you mean by thread safety here? It's not the global object that needs to be thread safe, it is the accessing code. If two threads write to a member variable near the same instant, one of them will "win", but is that a problem? If your client code depends on the global value staying constant until it is done with some unit of processing, then you will need to create a synchronization object for each property that needs to be locked. There isn't any great way around that. You could just cache a local copy of the value to avoid problems, but the applicability of that fix will depend on your circumstances. Also, I wouldn't create a synch object for each property by default, but instead as you realize you will need it.

PeterAllenWebb