1 using System; 2 using System.Collections; 3 using System.Collections.Generic; 4 using System.Threading; 5 6 namespace DbLinq.Util 7 { 8 /// <summary> 9 /// Thread Safe Dictionary Implementation (Brian Rudolph's code) 10 /// </summary> 11 /// <typeparam name="TKey">Type of Keys</typeparam> 12 /// <typeparam name="TValue">Type of Values</typeparam> 13 #if !MONO_STRICT 14 public 15 #endif 16 class ThreadSafeDictionary<TKey, TValue> : IThreadSafeDictionary<TKey, TValue> 17 { 18 //This is the internal dictionary that we are wrapping 19 IDictionary<TKey, TValue> dict; 20 ThreadSafeDictionary()21 public ThreadSafeDictionary() 22 { 23 this.dict = new Dictionary<TKey, TValue>(); 24 } 25 ThreadSafeDictionary(int capacity)26 public ThreadSafeDictionary(int capacity) 27 { 28 dict = new Dictionary<TKey, TValue>(capacity); 29 } 30 ThreadSafeDictionary(IEqualityComparer<TKey> comparer)31 public ThreadSafeDictionary(IEqualityComparer<TKey> comparer) 32 { 33 dict = new Dictionary<TKey, TValue>(comparer); 34 } 35 36 [NonSerialized] 37 ReaderWriterLockSlim dictionaryLock = Locks.GetLockInstance(LockRecursionPolicy.NoRecursion); //setup the lock; 38 39 /// <summary> 40 /// This is a blind remove. Prevents the need to check for existence first. 41 /// </summary> 42 /// <param name="key">Key to remove</param> RemoveSafe(TKey key)43 public void RemoveSafe(TKey key) 44 { 45 using (new ReadLock(this.dictionaryLock)) 46 { 47 if (this.dict.ContainsKey(key)) 48 { 49 using (new WriteLock(this.dictionaryLock)) 50 { 51 this.dict.Remove(key); 52 } 53 } 54 } 55 } 56 57 /// <summary> 58 /// Merge does a blind remove, and then add. Basically a blind Upsert. 59 /// </summary> 60 /// <param name="key">Key to lookup</param> 61 /// <param name="newValue">New Value</param> MergeSafe(TKey key, TValue newValue)62 public void MergeSafe(TKey key, TValue newValue) 63 { 64 using (new WriteLock(this.dictionaryLock)) // take a writelock immediately since we will always be writing 65 { 66 if (this.dict.ContainsKey(key)) 67 { 68 this.dict.Remove(key); 69 } 70 71 this.dict.Add(key, newValue); 72 } 73 } 74 Remove(TKey key)75 public virtual bool Remove(TKey key) 76 { 77 using (new WriteLock(this.dictionaryLock)) 78 { 79 return this.dict.Remove(key); 80 } 81 } 82 ContainsKey(TKey key)83 public virtual bool ContainsKey(TKey key) 84 { 85 using (new ReadOnlyLock(this.dictionaryLock)) 86 { 87 return this.dict.ContainsKey(key); 88 } 89 } 90 TryGetValue(TKey key, out TValue value)91 public virtual bool TryGetValue(TKey key, out TValue value) 92 { 93 using (new ReadOnlyLock(this.dictionaryLock)) 94 { 95 return this.dict.TryGetValue(key, out value); 96 } 97 } 98 99 public virtual TValue this[TKey key] 100 { 101 get 102 { 103 using (new ReadOnlyLock(this.dictionaryLock)) 104 { 105 return this.dict[key]; 106 } 107 } 108 set 109 { 110 using (new WriteLock(this.dictionaryLock)) 111 { 112 this.dict[key] = value; 113 } 114 } 115 } 116 117 public virtual ICollection<TKey> Keys 118 { 119 get 120 { 121 using (new ReadOnlyLock(this.dictionaryLock)) 122 { 123 return new List<TKey>(this.dict.Keys); 124 } 125 } 126 } 127 128 public virtual ICollection<TValue> Values 129 { 130 get 131 { 132 using (new ReadOnlyLock(this.dictionaryLock)) 133 { 134 return new List<TValue>(this.dict.Values); 135 } 136 } 137 } 138 Clear()139 public virtual void Clear() 140 { 141 using (new WriteLock(this.dictionaryLock)) 142 { 143 this.dict.Clear(); 144 } 145 } 146 147 public virtual int Count 148 { 149 get 150 { 151 using (new ReadOnlyLock(this.dictionaryLock)) 152 { 153 return this.dict.Count; 154 } 155 } 156 } 157 Contains(KeyValuePair<TKey, TValue> item)158 public virtual bool Contains(KeyValuePair<TKey, TValue> item) 159 { 160 using (new ReadOnlyLock(this.dictionaryLock)) 161 { 162 return this.dict.Contains(item); 163 } 164 } 165 Add(KeyValuePair<TKey, TValue> item)166 public virtual void Add(KeyValuePair<TKey, TValue> item) 167 { 168 using (new WriteLock(this.dictionaryLock)) 169 { 170 this.dict.Add(item); 171 } 172 } 173 Add(TKey key, TValue value)174 public virtual void Add(TKey key, TValue value) 175 { 176 using (new WriteLock(this.dictionaryLock)) 177 { 178 this.dict.Add(key, value); 179 } 180 } 181 Remove(KeyValuePair<TKey, TValue> item)182 public virtual bool Remove(KeyValuePair<TKey, TValue> item) 183 { 184 using (new WriteLock(this.dictionaryLock)) 185 { 186 return this.dict.Remove(item); 187 } 188 } 189 CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)190 public virtual void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) 191 { 192 using (new ReadOnlyLock(this.dictionaryLock)) 193 { 194 this.dict.CopyTo(array, arrayIndex); 195 } 196 } 197 198 public virtual bool IsReadOnly 199 { 200 get 201 { 202 using (new ReadOnlyLock(this.dictionaryLock)) 203 { 204 return this.dict.IsReadOnly; 205 } 206 } 207 } 208 GetEnumerator()209 public virtual IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() 210 { 211 throw new NotSupportedException("Cannot enumerate a threadsafe dictionary. Instead, enumerate the keys or values collection"); 212 } 213 IEnumerable.GetEnumerator()214 IEnumerator IEnumerable.GetEnumerator() 215 { 216 throw new NotSupportedException("Cannot enumerate a threadsafe dictionary. Instead, enumerate the keys or values collection"); 217 } 218 } 219 220 public static class Locks 221 { GetReadLock(ReaderWriterLockSlim locks)222 public static void GetReadLock(ReaderWriterLockSlim locks) 223 { 224 bool lockAcquired = false; 225 while (!lockAcquired) 226 lockAcquired = locks.TryEnterUpgradeableReadLock(1); 227 } 228 GetReadOnlyLock(ReaderWriterLockSlim locks)229 public static void GetReadOnlyLock(ReaderWriterLockSlim locks) 230 { 231 bool lockAcquired = false; 232 while (!lockAcquired) 233 lockAcquired = locks.TryEnterReadLock(1); 234 } 235 GetWriteLock(ReaderWriterLockSlim locks)236 public static void GetWriteLock(ReaderWriterLockSlim locks) 237 { 238 bool lockAcquired = false; 239 while (!lockAcquired) 240 lockAcquired = locks.TryEnterWriteLock(1); 241 } 242 ReleaseReadOnlyLock(ReaderWriterLockSlim locks)243 public static void ReleaseReadOnlyLock(ReaderWriterLockSlim locks) 244 { 245 if (locks.IsReadLockHeld) 246 locks.ExitReadLock(); 247 } 248 ReleaseReadLock(ReaderWriterLockSlim locks)249 public static void ReleaseReadLock(ReaderWriterLockSlim locks) 250 { 251 if (locks.IsUpgradeableReadLockHeld) 252 locks.ExitUpgradeableReadLock(); 253 } 254 ReleaseWriteLock(ReaderWriterLockSlim locks)255 public static void ReleaseWriteLock(ReaderWriterLockSlim locks) 256 { 257 if (locks.IsWriteLockHeld) 258 locks.ExitWriteLock(); 259 } 260 ReleaseLock(ReaderWriterLockSlim locks)261 public static void ReleaseLock(ReaderWriterLockSlim locks) 262 { 263 ReleaseWriteLock(locks); 264 ReleaseReadLock(locks); 265 ReleaseReadOnlyLock(locks); 266 } 267 GetLockInstance()268 public static ReaderWriterLockSlim GetLockInstance() 269 { 270 return GetLockInstance(LockRecursionPolicy.SupportsRecursion); 271 } 272 GetLockInstance(LockRecursionPolicy recursionPolicy)273 public static ReaderWriterLockSlim GetLockInstance(LockRecursionPolicy recursionPolicy) 274 { 275 return new ReaderWriterLockSlim(recursionPolicy); 276 } 277 } 278 279 public abstract class BaseLock : IDisposable 280 { 281 protected ReaderWriterLockSlim _Locks; 282 BaseLock(ReaderWriterLockSlim locks)283 public BaseLock(ReaderWriterLockSlim locks) 284 { 285 _Locks = locks; 286 } 287 Dispose()288 public abstract void Dispose(); 289 } 290 291 public class ReadLock : BaseLock 292 { ReadLock(ReaderWriterLockSlim locks)293 public ReadLock(ReaderWriterLockSlim locks) 294 : base(locks) 295 { 296 Locks.GetReadLock(this._Locks); 297 } 298 Dispose()299 public override void Dispose() 300 { 301 Locks.ReleaseReadLock(this._Locks); 302 } 303 } 304 305 public class ReadOnlyLock : BaseLock 306 { ReadOnlyLock(ReaderWriterLockSlim locks)307 public ReadOnlyLock(ReaderWriterLockSlim locks) 308 : base(locks) 309 { 310 Locks.GetReadOnlyLock(this._Locks); 311 } 312 Dispose()313 public override void Dispose() 314 { 315 Locks.ReleaseReadOnlyLock(this._Locks); 316 } 317 } 318 319 public class WriteLock : BaseLock 320 { WriteLock(ReaderWriterLockSlim locks)321 public WriteLock(ReaderWriterLockSlim locks) 322 : base(locks) 323 { 324 Locks.GetWriteLock(this._Locks); 325 } 326 Dispose()327 public override void Dispose() 328 { 329 Locks.ReleaseWriteLock(this._Locks); 330 } 331 } 332 } 333