2016-03-31 66 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