2016-03-31 29 views
1

我保持ReaderWriterLockSlim对象的字典资源访问:(示例代码是丑陋这里,只是让你明白我的目的)(C#)使汽车GC可能的解释<ReaderWriterLockSlim>

static ConcurrentDictionary<string, ReaderWriterLockSlim> rwResourceLocks = 
           new ConcurrentDictionary<string, ReaderWriterLockSlim>(); 

并使用像这样的:

if (ResourceStore.Exist("resourceID")) { 
    if (rwResourceLocks["resourceID"] == null) { 
     /* create a new lock in thread-safe way */ 
    } 
    rwResourceLocks["resourceID"].EnderReadLock(); 
    var rc = ResourceStore.GetResource("resourceID"); 
    /* further use of rc... */ 
    rwResourceLocks["resourceID"].ExitReadLock();  
} 

资源可动态增加或移除,其生命周期是不可预测的(无法mornitor去除资源),作为资源量成长,rwResourceLocks的尺寸也在增加,这将导致内存麻烦。有没有办法解决这个问题? (很明显,我不能简单地调用rwResourceLocks.Clear()来做到这一点)

我知道这是一个有点复杂:(

+0

有一个竞争条件:如果2个线程检查同样不存在'resourceID',然后他们都可以尝试创建新锁。希望这不是问题,或者你意识到这一点。目前还不清楚为什么你需要锁来访问的资源。你可以通过实现缓存来加速访问(如果这是一个目标)。否则,不知道资源是否正在使用是否可以释放它?如果是,则再次缓存。存储每个资源的最后访问时间,检查(定期或添加新资源时),过期时免费。 – Sinatr

+0

因为这些资源不仅用于读取,而且有时会进行修改,因此我会保留一个写入锁以防止在当时读取它。 (例如文件资源) – ineztia

回答

2

你可以尝试使用ConditionalWeakTable代替ConcurrentDictionary。一个ConditionalWeakTable自动删除值从字典时的密钥已经被垃圾收集器收集

ConditionalWeakTable<object, ReaderWriterLockSlim> _locks; 

if (ResourceStore.Exists("resourceID")) { 
    var rc = ResourceStore.GetResource("resourceID"); 
    var lck = _locks.GetValue(rc,() => new ReaderWriterLockSlim()); 

    lck.EnterReadLock(); 

    // Use the resource here 

    lck.ExitReadLock(); 
} 
+0

太棒了!顺便说一句,我有一个问题,对于像缓存整数值或字符串内容的一些非参考资源(因此WeakTable的Key不是一个对象),它仍然工作吗? @Wazner – ineztia

+0

不,ConditionalWeakTable要求它的键是一个引用类型(不是整数)。即使一个字符串是一个引用类型,也不建议这样做,因为在.NET中[string interning](https://en.wikipedia.org/wiki/String_interning)会导致它们的生存期很难预测。 – Wazner