Friday, February 4, 2011

Is this the proper use of a mutex?

I have a situation where I might have multiple instances of a program running at once, and it's important that just one specific function not be executing in more than one of these instances at once.

Is this the proper way to use a mutex to prevent this from happening?

lock (this.GetType()) {
    _log.Info("Doing Sync");
    DoSync();
    _log.Info("Sync Completed");
}
  • TheSeeker is correct.

    Jeff Richter's advice in Clr Via C# (p638-9) on locking is to create a private object specifically for the purpose of being locked.

    private Object _lock = new Object();
    
    // usage
    lock( _lock )
    {
        // thread-safe code here..
    }
    

    This works because _lock cannot be locked by anything outside the current class.

    EDIT: this is applicable to threads executing within a single process. @David Mohundro's answer is correct for inter-process locking.

  • @Jonathan Webb

    But in that case wont a second instance of the class create a different _lock Object, thus not preventing said second thread from executing this function at the same time as the first?

  • When you say "multiple instances" do you mean separate processes?

    If you do then you'll need to look at locking files, etc - rather than C# locks (Which will only protect multiple threads in a single process)

  • You said multiple instances of one application, so we're talking about two program.exe's running, right? The lock statement won't lock across multiple programs, just within the program. If you want a true Mutex, look at the System.Threading.Mutex object.

    Here is a usage example:

    bool createdNew;
    using (Mutex mtx = new Mutex(false, "MyAwesomeMutex", out createdNew))
    {
        try
        {
            mtx.WaitOne();
    
            MessageBox.Show("Click OK to release the mutex.");
        }
        finally
        {
            mtx.ReleaseMutex();
        }
    }
    

    The createdNew variable will let you know whether or not it was created the first time. It only tells you if it has been created, though. If you want to acquire the lock, you need to call WaitOne and then call ReleaseMutex to release it. If you just want to see if you created a Mutex, just constructing it is fine.

  • @Lawrence

    A second instance of the class will indeed create its own private instance of _lock but this is completely independent of the first class instance.

    If a thread is executing code inside the locked section of the first class instance, then any other thread will be blocked from that same block on the same instance. Threads can still execute that code section on other class instances.

    If the method and private lock objects were both static, then no threads could execute the locked section at all once one thread had done so.

    Does this help?

    J

  • @David Mohundro

    Thanks, I think that's really what I was looking for in the first place.

  • @Jonathan: Even easier:

    lock( this )
    {
        // thread-safe code here..
    }
    
    From Bob Nadler
  • @Bob

    Using lock( this ) { ... } is the way that Microsoft originally intended locking to work, but is flawed because it can lead to deadlocks if another thread locks the same object reference.

    Using a private dedicated object for locking means this can never happen.

    Jeff Richter explains this very well in CLR via C# (p636, Why the "Great" idea isn't so great after all). Well worth a read.

  • @Jonathan: I don't have the book you're referring to, but I dug around and now understand the issues with using lock(this) {...}. I found an interesting discussion on the topic.

    What's wrong with this code - #6

    What's wrong with this code #6? (Discussion)

    Eric provides reasoned guidance on the use of locks and the Synchronized wrapper and discusses some of the Microsoft Threading Design Guidelines.

    Jonathan Webb : @Bob Those are really good links. I do recommend reading CLR via C# if you can; it's a superb reference for .NET internals.
    From Bob Nadler

0 comments:

Post a Comment