25

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
            }
        }
    }
}
koen
  • 1,037
  • 3
  • 19
  • 27
  • 1
    Are you disposing of your XML file correctly (i.e. via `using`)? Can you share more code? Also, for static methods you should `lock` on private static objects, not on a type. See http://msdn.microsoft.com/en-us/library/c5kehkcz.aspx – Chris Schmich Oct 24 '10 at 21:33

2 Answers2

52

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
  • 51,692
  • 2
  • 65
  • 86
  • 3
    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.J. Oct 24 '10 at 21:52
  • 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 Oct 24 '10 at 21:54
  • Guess not: http://stackoverflow.com/questions/55984/what-is-the-difference-between-const-and-readonly – Cameron Skinner Oct 24 '10 at 22:23
  • Adding a "readonly" modifier to the lock object definition will prevent for change of the object reference. – Kryszal Feb 02 '16 at 19:40
38

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
  • 4,279
  • 1
  • 23
  • 29
  • 4
    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 Oct 24 '10 at 21:46