Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using a named mutex to lock a file

I'm using a named mutex to lock access to a file (with path 'strFilePath') in a construction like this:

private void DoSomethingsWithAFile(string strFilePath)
{
      Mutex mutex = new Mutex(false,strFilePath.Replace("\\",""));
      try
      {
         mutex.WaitOne();
         //do something with the file....
      }
      catch(Exception ex)
      {
         //handle exception
      }
      finally
      {
         mutex.ReleaseMutex();
      }
 }

So, this way the code will only block the thread when the same file is being processed already. Well, I tested this and seemed to work okay, but I really would like to know your thoughts about this.

like image 235
Jurgen Avatar asked Jan 31 '12 10:01

Jurgen


People also ask

How do you use a mutex lock?

The use of mutex locks is very easy. First, we need to declare a lock variable of type Mutex. Second, before entering the critical section that is protected by that lock, execute the Lock() method of that lock. Third, before exiting the critical section, execute the Unlock() method of the lock.

What is a named mutex?

Named mutex objects are used for inter-process synchronization because multiple applications can access the same mutex object. The mutex class is designed to protect a shared resource like memory, file handle or network connection from simultaneous access by multiple threads or processes.

What data does a mutex lock?

Mutex only locks a thread. It does not lock a resource. You can still access it via direct memory manipulation.

What happens if you try to lock a mutex that is already locked?

If the mutex is already locked by another thread, the thread waits for the mutex to become available. The thread that has locked a mutex becomes its current owner and remains the owner until the same thread has unlocked it.


2 Answers

Since you are talking about a producer-consumer situation with multiple threads the "standard solution would be to use BlockingCollection which is part of .NET 4 and up - several links with information:

  • http://msdn.microsoft.com/en-us/library/dd997371.aspx
  • http://blogs.msdn.com/b/csharpfaq/archive/2010/08/12/blocking-collection-and-the-producer-consumer-problem.aspx
  • http://geekswithblogs.net/BlackRabbitCoder/archive/2011/03/03/c.net-little-wonders-concurrentbag-and-blockingcollection.aspx
  • http://www.albahari.com/threading/part5.aspx

IF you just want to make the locking process work then:

use a ConcurrentDictionary in combination with the TryAdd method call... if it returns true then the file was not "locked" and is now "locked" so the thread can proceed - and "unlock" it by calling Remove at the end... any other thread gets false in the meantime and can decide what to do...

I would definitely recommend the BlockingCollection approach though!

like image 160
Yahia Avatar answered Oct 16 '22 08:10

Yahia


I ran into the same problem with many threads that can write in the same file.

The one of the reason that mutex not good because it slowly:

duration of call mutexSyncTest: 00:00:08.9795826    
duration of call NamedLockTest: 00:00:00.2565797

BlockingCollection collection - very good idea, but for my case with rare collisions, parallel writes better than serial writes. Also way with dictionary much more easy to realise.

I use this solution (UPDATED):

public class NamedLock
{
    private class LockAndRefCounter
    {
        public long refCount;
    }

    private ConcurrentDictionary<string, LockAndRefCounter> locksDictionary = new ConcurrentDictionary<string, LockAndRefCounter>();

    public void DoWithLockBy(string key, Action actionWithLock)
    {
        var lockObject = new LockAndRefCounter();

        var keyLock = locksDictionary.GetOrAdd(key, lockObject);
        Interlocked.Increment(ref keyLock.refCount);

        lock (keyLock)
        {
            actionWithLock();

            Interlocked.Decrement(ref keyLock.refCount);
            if (Interlocked.Read(ref keyLock.refCount) <= 0)
            {
                LockAndRefCounter removed;
                locksDictionary.TryRemove(key, out removed);
            }
        }
    }
}
like image 20
gabba Avatar answered Oct 16 '22 08:10

gabba