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

本文关键字:访问 命名为 创建 何创建 | 更新日期: 2024-07-23 06:26:14

我有一个基于字符串生成内容的类:

string Produce(string key);

结果被缓存,因此它只生成一个。现在我想锁定生产方法。我只想用这个方法锁定钥匙。。。如果有另一把钥匙进来,它不应该锁上。

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

我正在使用.Net 3.5

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

一个简单的字符串到对象锁定字典能工作吗?

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

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 "";
        }
    }
}

对此有一个非常规范的解决方案:

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

它具有以下重要特性:

  1. 它是安全的
  2. 给定密钥的值只生成一次(对于防止缓存踩踏和节省资源很重要)
  3. 阅读时无争用

可能会生成多个Lazy,但只有一个会被强制评估。