Lru cache算法以及他的锁的问题

来源:互联网 发布:python单行注释 编辑:程序博客网 时间:2024/06/04 19:51

Lru cache codes:

1. use double linked list for LRU.

2. For the lock, Do we need to put Get operation in lock or not?

    For example:  2.1.  this.cache.TryGetValue(key,out entry); in method GetItem(...);

            2.2. this.cache.ContainsKey(key) in method AddItem(...).

  For 2.1. We have to put it witin lock. because in method TryGetValue(key, out entry), it is not thread-safe.

           when one thread is get the entry index; then another thread delete the entry from entries, it is possible that entries[i] will return another entry value.

  For 2.2. this.cache.ContainsKey(key), which is still not thread-safe. I put it out of lock{}, maybe there is some risk.(it is safe if we put it in lock{}).


// It is from https://referencesource.microsoft.com/#mscorlib/system/collections/generic/dictionary.cs  


using System;using System.Collections.Generic;using System.Text;namespace LruCache_20170421{    public class LruCache<T>    {        public LruCache(int maxEntries)        {            if (maxEntries < 0)            {                throw new ArgumentOutOfRangeException("maxEntries", maxEntries, "maxEntries must be greater than or equal zero.");            }            this.maxEntries = maxEntries;        }        public bool LruCacheEnabled        {            get            {                return this.maxEntries > 0;            }        }        public void AddItem(string key, T item)        {            if (!LruCacheEnabled)            {                throw new ApplicationException("LruCache is disabled.");            }            if (string.IsNullOrEmpty(key))            {                throw new ArgumentNullException("key", "Key cannot be null or empty.");            }            if (this.cache.ContainsKey(key))            {                return;            }            lock (this.cache)            {                if (!this.cache.ContainsKey(key))                {                    if (this.cache.Count >= maxEntries)                    {                        RemoveOldestEntry();                    }                    CacheEntry cacheEntry = new CacheEntry();                    cacheEntry.Key = key;                    cacheEntry.Item = item;                    if (listEnd == null)                    {                        // set the first element in the list                        cacheEntry.Previous = null;                        cacheEntry.Next = null;                        listHead = cacheEntry;                        listEnd = cacheEntry;                    }                    else                    {                        AddElementToEnd(cacheEntry);                    }                    this.cache.Add(key, cacheEntry);                }            }        }        /// <summary>        /// add the element to the end of the list        /// </summary>        /// <param name="cacheEntry"></param>        private void AddElementToEnd(CacheEntry cacheEntry)        {            cacheEntry.Previous = listEnd;            cacheEntry.Next = null;            listEnd.Next = cacheEntry;            listEnd = cacheEntry;        }        public T GetItem(string key, out bool cached)        {            if (!LruCacheEnabled)            {                throw new ApplicationException("LruCache is disabled.");            }            if (string.IsNullOrEmpty(key))            {                //Logger.LogInformation("Key cannot be null or empty.");                cached = false;                return default(T);            }            T item = default(T);            CacheEntry entry;            lock (this.cache)            {                cached = this.cache.TryGetValue(key, out entry);                if (cached)                {                    item = entry.Item;                    #region move the element to the end of the list                    if (entry == listEnd)                    {                        return listEnd.Item;                    }                    if (entry == listHead)                    {                        // it is the head of the list                        // remove from the head                        listHead = entry.Next;                        listHead.Previous = null;                    }                    else // entry.Previous!=null                    {                        // remove from the list                        entry.Previous.Next = entry.Next;                        entry.Next.Previous = entry.Previous;                    }                    // add to the end                    AddElementToEnd(entry);                    #endregion                }            }            return item;        }        #region Private        /// <summary>        /// Remove the end entry, which is oldest.        /// </summary>        private void RemoveOldestEntry()        {            if (listHead == null) // cache is null.            {                return;            }            // remove the element in list head            CacheEntry entryToRemove = listHead;            string keyToRemove = entryToRemove.Key;            if (entryToRemove.Next != null)            {                entryToRemove.Next.Previous = null;            }            listHead = entryToRemove.Next;            if (listEnd == entryToRemove)            {                listEnd = listHead;            }            this.cache.Remove(keyToRemove);        }        private readonly Dictionary<string, CacheEntry> cache = new Dictionary<string, CacheEntry>();        private readonly int maxEntries;        private CacheEntry listHead; // element with the farest access time        private CacheEntry listEnd; // element with the nearest access time        private class CacheEntry        {            public string Key;            public T Item;            // double linked list            public CacheEntry Previous; // point the element with the far access time            public CacheEntry Next; // point the element with the near access time        }        #endregion    }}


0 0
原创粉丝点击