使用命名的互斥锁来锁定文件
我正在使用一个命名的互斥锁来锁定对文件的访问(使用路径’strFilePath’),如下所示:
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(); } }
因此,这样代码只会在处理相同文件时阻塞线程。 好吧,我测试了这个似乎工作正常,但我真的想知道你对此的想法。
由于您正在谈论具有多个线程的生产者 – 消费者情况,“标准解决方案是使用BlockingCollection
,它是.NET 4及更高版本的一部分 – 带有信息的几个链接:
- 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
如果您只是想使锁定过程工作,那么:
将ConcurrentDictionary
与TryAdd
方法调用结合使用…如果它返回true
则文件未被“锁定”并且现在被“锁定”,因此线程可以继续 – 并通过在末尾调用Remove
“解锁”它。任何其他线程在此期间都会变false
,并且可以决定做什么……
我肯定会推荐BlockingCollection
方法!
我遇到了许多可以在同一个文件中写入的线程遇到同样的问题。
互斥不好因为它慢慢的原因之一:
duration of call mutexSyncTest: 00:00:08.9795826 duration of call NamedLockTest: 00:00:00.2565797
BlockingCollection集合 – 非常好的主意,但对于我的罕见冲突情况,并行写入比串行写入更好。 字典也更容易实现。
我用这个解决方案( UPDATED ):
public class NamedLock { private class LockAndRefCounter { public long refCount; } private ConcurrentDictionary locksDictionary = new ConcurrentDictionary(); 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); } } } }
另一种方法是:创建一个在队列中工作的消费者线程,如果它是空的则阻塞。 您可以让多个生产者线程将多个文件路径添加到此队列并通知使用者。
从.net 4.0开始,有一个很好的新类: System.Collections.Concurrent.BlockingCollection
前一段时间我在Stack Overflow上遇到了同样的问题 – 如何实现我自己的高级生产者/消费者场景?