【问题标题】:(C#) make auto GC possible for Dictionary<ReaderWriterLockSlim>(C#) 使 Dictionary<ReaderWriterLockSlim> 的自动 GC 成为可能
【发布时间】:2016-03-31 10:04:07
【问题描述】:

我为资源访问维护了一个 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();    
}

资源可以动态添加或删除,并且它们的生命周期是不可预测的(无法监控资源的删除),随着资源量的增长,rwResourceLocks 的大小也会增加,这将导致内存问题。有没有办法解决这个问题? (显然我不能简单地调用 rwResourceLocks.Clear() 来做到这一点)

我知道这有点复杂:(

【问题讨论】:

  • 存在竞争条件:如果 2 个线程正在检查相同的不存在的resourceID,那么它们都可能会尝试创建新锁。希望这不是问题,或者您已经意识到这一点。目前尚不清楚为什么需要锁才能访问资源。您可以通过实现缓存来加快访问速度(如果这是一个目标)。否则在不知道资源是否正在使用的情况下可以释放它吗?如果是,则再次缓存。存储每个资源的最后访问时间,检查(定期或添加新资源时),过期时免费。
  • 因为这些资源不仅用于读取,而且有时会被修改,我会持有写锁以防止当时读取它。 (例如文件资源)

标签: c# thread-safety readerwriterlockslim readerwriterlock


【解决方案1】:

您可以尝试使用ConditionalWeakTable 而不是ConcurrentDictionaryConditionalWeakTable 会在垃圾收集器收集其键时自动从字典中删除一个值。

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();
}

【讨论】:

  • 太棒了!顺便说一句,我有一个问题,对于一些非引用资源,如缓存的整数值或字符串内容(因此 WeakTable 的键不是对象),它仍然有效吗? @Wazner
  • 不,ConditionalWeakTable 要求它的键是引用类型(整数不是)。即使字符串是引用类型,也不建议这样做,因为它们的生命周期很难预测,因为 .NET 中的string interning
猜你喜欢
  • 2011-06-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-18
  • 1970-01-01
  • 2021-11-21
  • 2016-02-15
  • 2011-03-01
相关资源
最近更新 更多