tags:

views:

56

answers:

3

I have a multi threaded application that writes to a settings xml file using a static method. I want to avoid that the file is being updated twice at the same time (causing accesss/write exception).

How do I do that?

This doesn't work:

namespace Program
{
    public class Settings
    {
        private static void SetSettingsValue (string settings, string value)
        {
            // make this thread safe to avoid writing to a locked settings xml file
            lock (typeof(Settings))
            {
                //write data to xml file
            }
        }
    }
}
A: 
static string SETTINGS_LOCK = "SETTINGS FILE";

later

lock(SETTINGS_LOCK)
Jason Goemaat
Thanks. I don't understand the lock() concept though. Why do I put the lock on a random string?
koen
@koen: the point is that you don't want to lock on a public type. See http://msdn.microsoft.com/en-us/library/c5kehkcz.aspx. Here, you should just define the lock object as `static object SettingsLock = new object();`.
Chris Schmich
@Jason: you never want to `lock` on a `string` due to C#'s string interning. See http://stackoverflow.com/questions/157511/using-lock-on-the-key-of-a-dictionarystring-object/157536#157536
Chris Schmich
I wouldn't say never, if you want to lock from multiple locations then you could just use the same string...
Jason Goemaat
+2  A: 

You should create a separate, static lock object and use that. DO NOT USE A STRING! Strings are automatically interned and there will be only one instance of each programmatically declared string so you can't guarantee exclusive access to the lock.

You should do this:

public class A {
    private static Object LOCK = new Object();

    private static void foo() {
        lock(LOCK) {
            // Do whatever
        }
    }
}

(The syntax may be incorrect; I'm a Java person mostly but the same rules about locking and String interning apply to C#)

The lock keyword enforces a mutual exclusion lock: only one thread can lock any particular object at a time. If a second thread calls foo then it will block until the first thread has exited the lock block.

Take home messages: for a static method lock on a private static variable. Don't lock on Strings or typeof(...) because you cannot guarantee that no-one else is using that object. Always lock on an object you know is not touched by anyone else by making it private and making it new.

Cameron Skinner
This is the best answer in the whole discussion. Because Cameron was wise enough to specify that the lock is private to the class.
C Johnson
It should also be whatever the C# equivalent of `final` is, but I'm not a C# guy so I'm not sure what that is. If C# has C++-style `const` then I think I'll switch from Java :)
Cameron Skinner
Guess not: http://stackoverflow.com/questions/55984/what-is-the-difference-between-const-and-readonly
Cameron Skinner
+2  A: 

The concept of lock() is to use an existing-object it can reference and use to control whether access is granted.

static object SpinLock = new object();

lock(SpinLock)
{
   //Statements
}

When the execution leaves the lock() block the reference is released and any other threads waiting to execute the code block can proceed (one at a time, of course).

Erik Noren
Note that you can't change the SpinLock reference inside the lock() statement itself. The object used for locking needs to be accessible by all the threads that need to execute the code and it can't change reference each time or the threads will never block each other and you'll get resource contention/conflicts.
Erik Noren