using System; using System.Collections.Generic; using System.Threading; //note, rewrite like ThreadSafeQueue namespace Svelto.DataStructures { /// /// original code: http://devplanet.com/blogs/brianr/archive/2008/09/29/thread-safe-dictionary-update.aspx /// simplified (not an IDictionary) and apdated (uses FasterList) /// /// /// [Serializable] public class ThreadSafeDictionary { public ThreadSafeDictionary(int v) { dict = new Dictionary(v); } public ThreadSafeDictionary() { dict = new Dictionary(); } // setup the lock; public virtual int Count { get { using (new ReadOnlyLock(dictionaryLock)) { return dict.Count; } } } public virtual bool IsReadOnly { get { using (new ReadOnlyLock(dictionaryLock)) { return dict.IsReadOnly; } } } public virtual FasterList Keys { get { using (new ReadOnlyLock(dictionaryLock)) { return new FasterList(dict.Keys); } } } public virtual FasterList Values { get { using (new ReadOnlyLock(dictionaryLock)) { return new FasterList(dict.Values); } } } public virtual TValue this[TKey key] { get { using (new ReadOnlyLock(dictionaryLock)) { return dict[key]; } } set { using (new WriteLock(dictionaryLock)) { dict[key] = value; } } } public virtual void Add(KeyValuePair item) { using (new WriteLock(dictionaryLock)) { dict.Add(item); } } public virtual void Clear() { using (new WriteLock(dictionaryLock)) { dict.Clear(); } } public virtual bool Contains(KeyValuePair item) { using (new ReadOnlyLock(dictionaryLock)) { return dict.Contains(item); } } public virtual void CopyTo(KeyValuePair[] array, int arrayIndex) { using (new ReadOnlyLock(dictionaryLock)) { dict.CopyTo(array, arrayIndex); } } public virtual bool Remove(KeyValuePair item) { using (new WriteLock(dictionaryLock)) { return dict.Remove(item); } } public virtual void Add(TKey key, TValue value) { using (new WriteLock(dictionaryLock)) { dict.Add(key, value); } } public virtual bool ContainsKey(TKey key) { using (new ReadOnlyLock(dictionaryLock)) { return dict.ContainsKey(key); } } public virtual bool Remove(TKey key) { using (new WriteLock(dictionaryLock)) { return dict.Remove(key); } } public virtual bool TryGetValue(TKey key, out TValue value) { using (new ReadOnlyLock(dictionaryLock)) { return dict.TryGetValue(key, out value); } } /// /// Merge does a blind remove, and then add. Basically a blind Upsert. /// /// Key to lookup /// New Value public void MergeSafe(TKey key, TValue newValue) { using (new WriteLock(dictionaryLock)) { // take a writelock immediately since we will always be writing if (dict.ContainsKey(key)) dict.Remove(key); dict.Add(key, newValue); } } /// /// This is a blind remove. Prevents the need to check for existence first. /// /// Key to remove public void RemoveSafe(TKey key) { using (new ReadLock(dictionaryLock)) { if (dict.ContainsKey(key)) using (new WriteLock(dictionaryLock)) { dict.Remove(key); } } } // This is the internal dictionary that we are wrapping readonly IDictionary dict; [NonSerialized] readonly ReaderWriterLockSlim dictionaryLock = Locks.GetLockInstance(LockRecursionPolicy.NoRecursion); } public static class Locks { public static ReaderWriterLockSlim GetLockInstance() { return GetLockInstance(LockRecursionPolicy.SupportsRecursion); } public static ReaderWriterLockSlim GetLockInstance(LockRecursionPolicy recursionPolicy) { return new ReaderWriterLockSlim(recursionPolicy); } public static void GetReadLock(ReaderWriterLockSlim locks) { var lockAcquired = false; while (!lockAcquired) lockAcquired = locks.TryEnterUpgradeableReadLock(1); } public static void GetReadOnlyLock(ReaderWriterLockSlim locks) { var lockAcquired = false; while (!lockAcquired) lockAcquired = locks.TryEnterReadLock(1); } public static void GetWriteLock(ReaderWriterLockSlim locks) { var lockAcquired = false; while (!lockAcquired) lockAcquired = locks.TryEnterWriteLock(1); } public static void ReleaseLock(ReaderWriterLockSlim locks) { ReleaseWriteLock(locks); ReleaseReadLock(locks); ReleaseReadOnlyLock(locks); } public static void ReleaseReadLock(ReaderWriterLockSlim locks) { if (locks.IsUpgradeableReadLockHeld) locks.ExitUpgradeableReadLock(); } public static void ReleaseReadOnlyLock(ReaderWriterLockSlim locks) { if (locks.IsReadLockHeld) locks.ExitReadLock(); } public static void ReleaseWriteLock(ReaderWriterLockSlim locks) { if (locks.IsWriteLockHeld) locks.ExitWriteLock(); } } public abstract class BaseLock : IDisposable { protected ReaderWriterLockSlim _Locks; public BaseLock(ReaderWriterLockSlim locks) { _Locks = locks; } public abstract void Dispose(); } public class ReadLock : BaseLock { public ReadLock(ReaderWriterLockSlim locks) : base(locks) { Locks.GetReadLock(_Locks); } public override void Dispose() { Locks.ReleaseReadLock(_Locks); } } public class ReadOnlyLock : BaseLock { public ReadOnlyLock(ReaderWriterLockSlim locks) : base(locks) { Locks.GetReadOnlyLock(_Locks); } public override void Dispose() { Locks.ReleaseReadOnlyLock(_Locks); } } public class WriteLock : BaseLock { public WriteLock(ReaderWriterLockSlim locks) : base(locks) { Locks.GetWriteLock(_Locks); } public override void Dispose() { Locks.ReleaseWriteLock(_Locks); } } }