我正在编写一个自定义字典,它将用作缓存的助手。我使用委托的原因是因为它必须与生成的代码接口,所以我不能更改它。但是,您可以假设委托是线程安全的。我做了一些初步的测试,它是线程安全的,但我总是可以使用额外的一对眼睛来发现可能的并发问题。
//StoreToCache will handle removal, replacement, and addition to the cache
public delegate object StoreToCache(string key, object value, CacheObject info);
public delegate object GetFromCache(string key);
/// <summary>
/// A super fast concurrent "dictionary" which passes through to the generated Cache class which constructed it.
/// </summary>
public class CacheDictionary<K,V>
{
ConcurrentDictionary<K, string> RealKeys=new ConcurrentDictionary<K, string>();
readonly string BaseKey;
readonly CacheObject Info;
StoreToCache StoreTo;
GetFromCache GetFrom;
/// <summary>
/// This returns the amount of keys we are tracking within this CacheDictionary.
/// Note: This does not necessarily indicate how many items are actually still in the cache!
/// </summary>
/// <returns>
/// The count.
/// </returns>
public int TrackedCount
{
get
{
return RealKeys.Count;
}
}
public CacheDictionary(string basekey, CacheObject info, StoreToCache store, GetFromCache get)
{
BaseKey=basekey;
Info=info;
StoreTo=store;
GetFrom=get;
}
void Add (K key, V value)
{
string realkey=RealKeys.GetOrAdd(key, (s) => AddKey(key));
StoreTo(realkey, value, Info);
}
public V Remove (K key)
{
var res=StoreTo(GetKey(key), null, Info);
string trash=null;
RealKeys.TryRemove(key, out trash);
if(res!=null && res is V)
{
return (V)res;
}
else
{
return default(V);
}
}
static long CurrentKey=0;
string AddKey(K key)
{
long tmp=Interlocked.Increment(ref CurrentKey);
string k=BaseKey+(tmp).ToString();
if(!RealKeys.TryAdd(key, k))
{
return null;
}
return k;
}
string GetKey(K key)
{
string tmp=null;
if(!RealKeys.TryGetValue(key, out tmp))
{
return null;
}
return tmp;
}
public V this [K key] {
get {
string realkey=GetKey(key);
if(realkey==null)
{
return default(V);
}
object tmp=GetFrom(realkey);
if(tmp!=null && tmp is V)
{
return (V)tmp;
}
else
{
string trash=null;
RealKeys.TryRemove(key, out trash); //cleanup
return default(V);
}
}
set {
if(value==null)
{
Remove(key);
}
else
{
Add (key, value);
}
}
}
public void Clear ()
{
lock(RealKeys)
{
foreach(var key in RealKeys.Keys)
{
//don't worry about concurrency here. Iterating over the collection is so non-thread-safe it's not even funny.
StoreTo(GetKey(key), null, Info);
}
RealKeys.Clear();
}
}
}这个代码线程安全吗?还假设委托可以返回基本上随机的值,因为它们传递到缓存。因此,它们可能在任何时候都具有所要求的价值,也可能没有。如果委托没有请求的值,它将返回null。
这个字典总是被初始化为静态的,并且基本上可以同时从无限数量的线程中访问。它不应该抛出任何一种例外。如果一个值不存在,它应该返回null。
这个线程在任何情况下都安全吗?另外,有什么东西可以使代码更加清晰吗?
用例如下所示:
static ConcurrentDictionary<int, string> d=new ConcurrencyDictionary....
....
d[10]="foo"; //add a value if it doesn't exist
d[10]=null; //remove value if it exists
string tmp=d[1]; //read value. returns the value if it exists, else null发布于 2012-12-09 14:30:46
您的代码不安全:
RealKeysClear并不会阻止其他方法更新RealKeys,因为其他方法不会锁定RealKeys。其他有代码值得注意的问题:
CacheDictionary不需要了解CacheObject。相反,如果“真正的缓存”实现了一个接口,并且它是作为缓存实现而不是两个委托传递的,那就更好了。ConcurrentDictionary<TKey, TValue>或System.Runtime.Caching.MemoryCache可能是个好主意。https://codereview.stackexchange.com/questions/19411
复制相似问题