Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/vue.js/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 用于维护线程安全缓存的类_C#_.net_Multithreading_Synchronization_Readerwriterlockslim - Fatal编程技术网

C# 用于维护线程安全缓存的类

C# 用于维护线程安全缓存的类,c#,.net,multithreading,synchronization,readerwriterlockslim,C#,.net,Multithreading,Synchronization,Readerwriterlockslim,我正在开发一个线程安全类,用作缓存,它应该可以在.NET和Mono中工作 这些项都有生存时间,每次检索对象时,都会刷新其生存时间。每次添加项目时,时间戳都会添加到另一个包含相同键的集合中。计时器引发查找过期项目并将其删除的方法 当我尝试获取和项时,我还必须提供一个委托,指示如果缓存中不存在该委托,如何获取该委托 我做过测试,虽然在测试中项目移除应该每30秒进行一次,但它经常发生,几乎每秒钟都会发生,我不知道为什么 这是一节课: public class GenericCache<T

我正在开发一个线程安全类,用作缓存,它应该可以在.NET和Mono中工作

这些项都有生存时间,每次检索对象时,都会刷新其生存时间。每次添加项目时,时间戳都会添加到另一个包含相同键的集合中。计时器引发查找过期项目并将其删除的方法

当我尝试获取和项时,我还必须提供一个委托,指示如果缓存中不存在该委托,如何获取该委托

我做过测试,虽然在测试中项目移除应该每30秒进行一次,但它经常发生,几乎每秒钟都会发生,我不知道为什么

这是一节课:

    public class GenericCache<TId, TItem>:IDisposable where TItem : class
{
    SortedDictionary<TId, TItem> _cache;
    SortedDictionary<TId, DateTime> _timeouts;
    Timer _timer;
    Int32 _cacheTimeout;
    System.Threading.ReaderWriterLockSlim _locker;

    public GenericCache(Int32 minutesTTL)
    {
        _locker = new System.Threading.ReaderWriterLockSlim();
        _cacheTimeout = minutesTTL;
        _cache = new SortedDictionary<TId, TItem>();
        _timeouts = new SortedDictionary<TId, DateTime>();
        _timer = new Timer((minutesTTL * 60) / 2);
        _timer.Elapsed += new ElapsedEventHandler(_timer_Elapsed);
        _timer.AutoReset = true;
        _timer.Enabled = true;
        _timer.Start();
    }

    /// <summary>
    /// Get an item, if it doesn't exist, create it using the delegate
    /// </summary>
    /// <param name="id">Id for the item</param>
    /// <param name="create">A delegate that generates the item</param>
    /// <returns>The item</returns>
    public TItem Get(TId id, Func<TItem> create)
    {
        _locker.EnterUpgradeableReadLock();
        try
        {
            TItem item = _cache.Where(ci => ci.Key.Equals(id)).Select(ci => ci.Value).SingleOrDefault();
            if (item == null)
            {
                _locker.EnterWriteLock();
                // check again, maybe another thread is waiting in EnterWriteLock cos the same item is null
                item = _cache.Where(ci => ci.Key.Equals(id)).Select(ci => ci.Value).SingleOrDefault();
                if (item == null)
                {
                    Debug.Write("_");
                    item = create.Invoke();
                    if (item != null)
                    {
                        _cache.Add(id, item);
                        _timeouts.Add(id, DateTime.Now);
                    }
                }
            }
            else
                _timeouts[id] = DateTime.Now;

            return item;
        }
        finally
        {
            if(_locker.IsWriteLockHeld)
                _locker.ExitWriteLock();
            _locker.ExitUpgradeableReadLock();
        }
    }

    /// <summary>
    /// Execute a delegate in the items, for example clear nested collections.
    /// </summary>
    /// <param name="action">The delegate</param>
    public void ExecuteOnItems(Action<TItem> action)
    {
        _locker.EnterWriteLock();
        try
        {
            foreach (var i in _cache.Values)
                action.Invoke(i);
        }
        finally
        {
            _locker.ExitWriteLock();
        }
    }

    /// <summary>
    /// Clear this cache
    /// </summary>
    public void Clear()
    {
        _locker.EnterWriteLock();
        try
        {
            _cache.Clear();
            _timeouts.Clear();
        }
        finally
        {
            _locker.ExitWriteLock();
        }
    }

    /// <summary>
    /// Remove outdated items
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void _timer_Elapsed(object sender, ElapsedEventArgs e)
    {
        _locker.EnterUpgradeableReadLock();
        try
        {
            var delete = _timeouts.Where(to => DateTime.Now.Subtract(to.Value).TotalMinutes > _cacheTimeout).ToArray();

            if(delete.Any())
            {
                _locker.EnterWriteLock();
                foreach (var timeitem in delete)
                {
                    Debug.Write("-");
                    _cache.Remove(timeitem.Key);
                    _timeouts.Remove(timeitem.Key);
                }
            }
        }
        finally
        {
            if(_locker.IsWriteLockHeld)
                _locker.ExitWriteLock();
            _locker.ExitUpgradeableReadLock();
        }
    }

    #region IDisposable Members
    private volatile Boolean disposed = false;
    protected virtual void Dispose(bool disposing)
    {
        if (!disposed)
        {
            if (disposing)
            try
            {
                this.Clear();
            }
            finally
            {
                _locker.Dispose();
            }

            disposed = true;
        }
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    ~GenericCache()
    {
        Dispose(false);
    }

    #endregion
}
公共类GenericCache:IDisposable,其中TItem:class
{
分类字典缓存;
分类词典超时;
定时器(u定时器),;
Int32\u缓存超时;
System.Threading.ReaderWriterLockSlim\u locker;
公共通用缓存(Int32分钟测试TL)
{
_locker=新的System.Threading.ReaderWriterLockSlim();
_cacheTimeout=minutestl;
_缓存=新的SortedDictionary();
_超时=新的SortedDictionary();
_定时器=新定时器((分钟数TL*60)/2);
_timer.appeased+=新的ElapsedEventHandler(_timer_appeased);
_timer.AutoReset=true;
_timer.Enabled=true;
_timer.Start();
}
/// 
///获取一个项,如果它不存在,则使用委托创建它
/// 
///项目的Id
///生成项目的委托
///项目
公共TItem Get(TId id,Func create)
{
_locker.EnterUpgradeableReadLock();
尝试
{
TItem item=_cache.Where(ci=>ci.Key.Equals(id)).Select(ci=>ci.Value.SingleOrDefault();
如果(项==null)
{
_locker.EnterWriteLock();
//再次检查,可能另一个线程正在EnterWriteLock中等待,因为同一项为空
item=_cache.Where(ci=>ci.Key.Equals(id)).Select(ci=>ci.Value.SingleOrDefault();
如果(项==null)
{
Debug.Write(“”);
item=create.Invoke();
如果(项!=null)
{
_cache.Add(id,item);
_添加(id,DateTime.Now);
}
}
}
其他的
_超时[id]=DateTime.Now;
退货项目;
}
最后
{
如果(_locker.iswritelockhold)
_locker.ExitWriteLock();
_locker.ExitUpgradeableReadLock();
}
}
/// 
///在项中执行委托,例如清除嵌套集合。
/// 
///代表
public void ExecuteOnItems(操作)
{
_locker.EnterWriteLock();
尝试
{
foreach(vari在_cache.Values中)
行动.援引(i);
}
最后
{
_locker.ExitWriteLock();
}
}
/// 
///清除此缓存
/// 
公共空间清除()
{
_locker.EnterWriteLock();
尝试
{
_cache.Clear();
_超时。清除();
}
最后
{
_locker.ExitWriteLock();
}
}
/// 
///删除过时的项目
/// 
/// 
/// 
私有无效时间已过(对象发送方,ElapsedEventArgs e)
{
_locker.EnterUpgradeableReadLock();
尝试
{
var delete=_timeouts.Where(to=>DateTime.Now.Subtract(to.Value.TotalMinutes>_cacheTimeout.ToArray();
if(delete.Any())
{
_locker.EnterWriteLock();
foreach(删除中的var timeitem)
{
Debug.Write(“-”);
_cache.Remove(timeitem.Key);
_timeouts.Remove(timeitem.Key);
}
}
}
最后
{
如果(_locker.iswritelockhold)
_locker.ExitWriteLock();
_locker.ExitUpgradeableReadLock();
}
}
#区域IDisposable成员
private=false;
受保护的虚拟void Dispose(bool disposing)
{
如果(!已处置)
{
如果(处置)
尝试
{
这个.Clear();
}
最后
{
_locker.Dispose();
}
这是真的;
}
}
公共空间处置()
{
处置(真实);
总干事(本);
}
~GenericCache()
{
处置(虚假);
}
#端区
}
如您所见,在调试模式下,当添加一个项时,将打印一个“u”符号,当删除和项时,将打印一个“-”符号。在测试中,在第二分钟后,我可以看到项目是如何在同一秒内删除和添加的,而项目只应每30秒删除一次,我不知道为什么:

我就是这样测试的:

        static void Main(string[] args)
    {
        GenericCache<Int32, String> cache = new GenericCache<Int32, String>(1);

        Debug.Listeners.Add(new ConsoleTraceListener());

        Action a = delegate()
        {
            Random r = new Random(DateTime.Now.Millisecond);
            while (true)
            {
                Int32 number = r.Next(0, 9999);
                if (String.IsNullOrEmpty(cache.Get(number, () => number.ToString())))
                    Debug.Write("E");
                Thread.Sleep(number);
            }
        };

        for (int i = 0; i < 150; i++)
        {
            new Thread(new ThreadStart(a)).Start();
            Thread.Sleep(5);
        }

        Console.ReadKey();
    }
static void Main(字符串[]args)
{
GenericCache=新的GenericCache(1);
添加(新的ConsoleTraceListener());
动作a=委托()
{
Random r=新随机数(DateTime.Now.毫秒);
while(true)
{
Int32 number=r.Next(0,9999);
if(String.IsNullOrEmpty(cache.Get(number,()=>number.ToString()))
Debug.Write(“E”);
线程。睡眠(数字);
}
};
对于(int i=0;i<150;i++)
{
新线程(newthreadstart(a)).Start();
睡眠(5);
}
Console.ReadKey();
}
您看到GenericCache类中有任何问题吗

提前感谢,致以亲切的问候。

我看到的第一期(假设您正在使用Sy
  _timer = new Timer((minutesTTL * 60000) / 2);