锁定自加载缓存
我正在C#中实现一个简单的缓存,并试图使其可以从多个线程访问。在基本阅读的情况下,很容易:锁定自加载缓存
var cacheA = new Dictionary<int, MyObj>(); // Populated in constructor
public MyObj GetCachedObjA(int key)
{
return cacheA[key];
}
这是,我相信,完全是线程安全的。但我也想让它自动加载。也就是说,如果缓存未在访问时填充,则在满足访问请求之前将其填充。
Dictionary<int, MyObj> cacheB = null;
public MyObj GetCachedObjB(int key)
{
if (cacheB == null)
{
PopulateCacheB();
}
return cacheB[key];
}
private void PopulateCacheB()
{
cacheB = new Dictionary<int, MyObj>();
foreach (MyObj item in databaseAccessor)
{
cacheB.Add(item.Key, item);
}
}
这不是线程安全的,因为cacheB实例化后,一个线程可以访问GetCachedObjB但在此之前它是完全填充,如果另一个线程是填充它的过程。 那么在cacheB上执行锁定以便缓存是线程安全的最佳方式是什么?
可以使用lock
语句简单的线程安全:
private Dictionary<int, MyObj> cacheB = null;
private readonly object cacheLockB = new object();
public MyObj GetCachedObjB(int key)
{
lock (cacheLockB)
{
if (cacheB == null)
{
Dictionary<int, MyObj> temp = new Dictionary<int, MyObj>();
foreach (MyObj item in databaseAccessor)
{
temp.Add(item.Key, item);
}
cacheB = temp;
}
return cacheB[key];
}
}
如果你需要比lock
挤出更多的性能允许,那么你可以使用一个ReaderWriterLockSlim
代替,这将允许多个线程读取字典同时。当您需要填充或更新字典时,可以将锁升级到写入模式。
像这样: http://devplanet.com/blogs/brianr/archive/2008/09/26/thread-safe-dictionary-in-net.aspx
你的第一个例子是不是在所有线程安全的。如果有人插入另一个人从地图上取东西时该怎么办?插入可能会改变字典,这意味着阅读它可以访问损坏的状态
您可以使用线程安全的Enterprise Library Cache。
在监视器中包装填充操作。这样,如果另一个线程在填充缓存时尝试读取缓存,那么在它尝试读取之前,线程将*等待填充操作完成/错误。
您也可以做到这一点的读取停止,而你从中读取被修改的高速缓存,在这种情况下,你需要读入一个临时变量,释放监视器,然后返回变量或你会遇到锁定问题。
public MyObj GetCachedObjB(int key)
{
try {
Monitor.Enter(cacheB);
if (cacheB == null)
{
PopulateCacheB();
}
} finally {
Monitor.Exit(cacheB);
}
return cacheB[key];
}
作为一般记它,你不妨做时添加一些关键的验证读取你的字典,虽然这取决于你是否要对不存在的密钥或一些默认值的误差。
假设你的词典是线程安全的或只读人口后,你可以在这样一个线程安全的方式来填充它:
private void PopulateCacheB()
{
Dictionary<int, MyObj>() dictionary = new Dictionary<int, MyObj>();
foreach (MyObj item in databaseAccessor)
{
dictionary.Add(item.Key, item);
}
cacheB = dictionary;
}
在最坏情况下的数据将来自“databaseAccessor”检索超过一旦出现竞赛状况,但这不应该受到伤害。
任何不使用“锁定”语句而不是所有“尝试...输入...终于...退出”的东西的原因? http://msdn.microsoft.com/en-us/library/c5kehkcz.aspx – LukeH 2009-06-30 17:09:59