如何在C#中创建“命名互斥访问”?

时间:2013-12-05 16:05:01

标签: c# .net locking mutex

我有一个基于字符串生成东西的类:

string Produce(string key);

结果是缓存的,因此只生成一个。现在我想锁定生产方法。我只希望方法锁定密钥......如果另一个密钥进入,它不应该锁定。

我已从lock切换到命名Mutex,但我读到这个方法很慢,因为Mutex是操作系统范围的。我将如何创建一些命名锁?

我正在使用.Net 3.5

3 个答案:

答案 0 :(得分:2)

对象锁定字典的简单字符串是否有效?

object _superLock = new object();
Dictionary<string, object> _locks = new Dictionary<string, object>();

string Produce(string key) {
    lock(GetLock(key)) {
        // do stuff
    }
}

object GetLock(string key) {
    lock(_superLock) {
        if (!_locks.ContainsKey(key)) {
            _locks[key] = new object();
        }
    }
    return _locks[key];
}

更新:哦,对了,ConcurrentDictionary存在。这可能看起来像

ConcurrentDictionary<string, object> _locks = new ConcurrentDictionary<string, object>();
object GetLock(string key) {
    return _locks.GetOrAdd(key, k => new object());
}

答案 1 :(得分:1)

ConcurrentDictionary让这很容易:

public class Foo
{
    private ConcurrentDictionary<string, object> locks =
        new ConcurrentDictionary<string, object>();

    public string Produce(string key)
    {
        lock (locks.GetOrAdd(key, new object()))
        {
            //TODO do whatever
            return "";
        }
    }
}

答案 2 :(得分:0)

这有很多规范的解决方案:

var cacheItems = new ConcurrentDictionary<TKey, Lazy<TValue>>();
...
TValue Get(Func<TValue> factory) {
 return cacheItems.GetOrAdd(_ => new Lazy<TValue>(factory)).Value;
}

这具有以下重要属性:

  1. 很安全。
  2. 给定密钥的值只生成一次(对于防止缓存冲压和节省资源很重要)。
  3. 阅读时没有争用。
  4. 可能会产生多个Lazy,但只有一个会被迫评估。