Using a named mutex to lock a file

I use a named mutex to block access to the file (with the path "strFilePath") in this construct:

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(); } } 

Thus, this code will block the thread only when the same file is already being processed. Well, I checked it and it seemed to work fine, but I really would like to know your thoughts about it.

+6
source share
3 answers

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

IF you just want to make the locking process as follows:

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

I would definitely recommend the BlockingCollection approach, though!

+3
source

An alternative could be: create one consumer thread that runs in the queue and blocks if it is empty. You can have several producer threads adding several file paths to this queue and informing the user.

Since .net 4.0 there is a new class: System.Collections.Concurrent.BlockingCollection<T>

Some time ago I had the same problem in the Stack Overflow section. How to implement your own extended producer / consumer scenario?

+1
source

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

One of the reasons that a mutex is not good is because it is slow:

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

The BlockingCollection is a very good idea, but for my rare collision case, parallel recording is better than serial recording. Also, the dictionary path is much easier to implement.

I am using 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); } } } } 
+1
source

Source: https://habr.com/ru/post/907298/


All Articles