【问题标题】:How to create "named mutual exclusive access" in C#?如何在 C# 中创建“命名互斥访问”?
【发布时间】:2013-12-05 16:05:00
【问题描述】:

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

string Produce(string key);

结果被缓存,所以它只产生一个。现在我想锁定生产方法。我只想要锁定钥匙的方法...如果另一个钥匙进来,它不应该锁定。

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

我正在使用 .Net 3.5

【问题讨论】:

    标签: c# .net locking mutex


    【解决方案1】:

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

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

    【讨论】:

    • 哇...听起来不错...我会尝试把它变成一个类。我想知道.Net 是否没有这样的东西。它“感觉”很初级。
    • 使用 ConcurrentDictionary 而不是一个简单的手动锁定。
    • @chase,我还在 3.5 :(
    • 这不是一个错误,这是一个定义明确的行为。对于给定的键,工厂可能会被多次调用,但只有一个结果值会被持久化(并从GetOrAdd 返回)。
    • 我假设他的值缓存机制已经涵盖了这一点,只有在缓存还没有值时才会调用 Produce。
    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

      对此有相当规范的解决方案:

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

      这具有以下重要属性:

      1. 很安全。
      2. 给定键的值只生成一次(对于防止缓存标记和节省资源很重要)。
      3. 读取时无争用。

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-11-04
        • 2011-01-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-09-24
        相关资源
        最近更新 更多