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