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