【问题标题】:Is this ConcurrentDictionary Thread safe?这个 ConcurrentDictionary 线程安全吗?
【发布时间】:2018-07-02 14:21:11
【问题描述】:

这是 ConcurrentDictionary ThreadSafe 吗?

    private static ConcurrentDictionary<string, DateTime> dictionary= new ConcurrentDictionary<string, DateTime>();

    public bool TextInputRecently(string text)
    {
        dictionary = new ConcurrentDictionary<string, DateTime>( dictionary.Where(pair => pair.Value.Ticks >= DateTime.Now.AddMinutes(-5).Ticks)
                             .ToDictionary(pair => pair.Key,
                                           pair => pair.Value));

        if (dictionary.ContainsKey(text))
            return true;

        dictionary.TryAdd(text, DateTime.Now);
        return false;
    }

我认为这不是因为在另一个线程正在检查密钥是否存在时可以重新创建字典。

在字典中循环删除过期值会更好吗?

【问题讨论】:

  • 也许您正在寻找的是缓存,例如MemoryCache。它是线程安全的并且可以处理过期问题,因此您不必检查条目日期或“手动”删除过期条目。

标签: c#


【解决方案1】:

没有;字典可以在 ContainsKey()TryAdd() 之间变化。

你永远不应该在 ConcurrentDictionary 上连续调用两个方法,除非你确定你不在乎它们之间的变化。
同样,您不能循环遍历字典,因为它可能会在循环过程中发生变化。

相反,您应该使用其更复杂的方法(例如 TryAdd(),它将检查并添加单个原子操作。

此外,正如您所建议的,整个字典可能会被替换。

【讨论】:

    【解决方案2】:

    感谢 SLaks 的回答。

    我遵循了 Scott Hannen 的建议并将其替换为 MemoryCache。这是代码以防有人需要,后面跟着Locking pattern for proper use of .NET MemoryCache

    private static MemoryCache cache;
        static readonly object cacheLock = new object();
        private int expiry_timeout = 5;
    
        public bool TextInputRecently(string text)
        {
            //Returns null if the string does not exist, prevents a race condition where the cache invalidates between the contains check and the retrieval.
            var cachedString = MemoryCache.Default.Get(text, null) as string;
    
            if (cachedString != null)
                return true;
    
            lock (cacheLock)
            {
                //Check to see if anyone wrote to the cache while we where waiting our turn to write the new value.
                cachedString = MemoryCache.Default.Get(text, null) as string;
    
                if (cachedString != null)
                    return true;
    
                //The value still did not exist so we now write it in to the cache.                
                CacheItemPolicy cip = new CacheItemPolicy()
                {
                    AbsoluteExpiration = new DateTimeOffset(DateTime.Now.AddSeconds(expiry_timeout))
                };
                MemoryCache.Default.Set(text, "", cip);
                return false;
            }
        }        
    

    可能有更好的解决方案,但这可以满足我的需求。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多