using System; using System.Collections.Generic; using System.Collections.Concurrent; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; /// http://download.microsoft.com/download/B/C/F/BCFD4868-1354-45E3-B71B-B851CD78733D/PerformanceCharacteristicsOfThreadSafeCollection.pdf namespace tgcs.Util.Concurrency { /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public class ConcurrentList<T> : ConcurrentContainer<T> { readonly List<T> list = new List<T>(); SpinLock m_lock = new SpinLock(); // do not make this 'readonly' int c_inert = 0; public override void Clear() { bool entered = false; try { m_lock.Enter(ref entered); list.Clear(); } finally { if (entered) m_lock.Exit(); } } public override bool Add(T item) { bool entered = false; try { m_lock.Enter(ref entered); list.Add(item); return true; } finally { if (entered) m_lock.Exit(); } } /// <summary> /// (useless for concurrency) /// </summary> public override bool Contains(T item) { bool entered = false; try { m_lock.Enter(ref entered); return list.Contains(item); } finally { if (entered) m_lock.Exit(); } } /// <summary> /// (useless for concurrency) /// </summary> public override int Count { get { bool entered = false; try { m_lock.Enter(ref entered); return list.Count - c_inert; } finally { if (entered) m_lock.Exit(); } } } public override IEnumerator<T> GetEnumerator() { int i = 0; while (true) { bool entered = false; try { m_lock.Enter(ref entered); while (true) { if (i >= list.Count) yield break; else { T item = list[i++]; // exiting a 'try' block with 'yield return' does not execute 'finally' each time // http://blogs.msdn.com/b/oldnewthing/archive/2008/08/14/8862242.aspx entered = false; m_lock.Exit(); yield return item; m_lock.Enter(ref entered); break; } } } finally { if (entered) m_lock.Exit(); } } } public T[] ToArray() { bool entered = false; try { m_lock.Enter(ref entered); return list.ToArray(); } finally { if (entered) m_lock.Exit(); } } /// <summary> /// Would interfere with in-situ enumeration /// </summary> public override bool Remove(T item) { throw new NotSupportedException(); } }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public class ConcurrentHashSet<T> : ConcurrentContainer<T> { readonly HashSet<T> hs = new HashSet<T>(); SpinLock m_lock = new SpinLock(); // do not make this 'readonly' T any = default(T); public T Peek() { return any; } public override bool Add(T item) { bool entered = false; try { m_lock.Enter(ref entered); bool b = hs.Add(item); if (b) any = item; return b; } finally { if (entered) m_lock.Exit(); } } public override bool Remove(T item) { bool entered = false; try { m_lock.Enter(ref entered); bool b = hs.Remove(item); if (b && any.Equals(item)) { if (hs.Count == 0) any = default(T); else { var e = hs.GetEnumerator(); e.MoveNext(); any = e.Current; } } return b; } finally { if (entered) m_lock.Exit(); } } public override void Clear() { bool entered = false; try { m_lock.Enter(ref entered); hs.Clear(); any = default(T); } finally { if (entered) m_lock.Exit(); } } public override bool Contains(T item) { bool entered = false; try { m_lock.Enter(ref entered); return hs.Contains(item); } finally { if (entered) m_lock.Exit(); } } public T[] ToArray() { bool entered = false; try { m_lock.Enter(ref entered); return hs.ToArray(); } finally { if (entered) m_lock.Exit(); } } public override int Count { get { return hs.Count; } } }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public class ConcurrentStringBuilder { readonly StringBuilder sb = new StringBuilder(); SpinLock m_lock = new SpinLock(); // do not make this 'readonly' public void Clear() { bool entered = false; try { m_lock.Enter(ref entered); sb.Clear(); } finally { if (entered) m_lock.Exit(); } } public ConcurrentStringBuilder Append(String s) { bool entered = false; try { m_lock.Enter(ref entered); sb.Append(s); return this; } finally { if (entered) m_lock.Exit(); } } public ConcurrentStringBuilder AppendFormat(String fmt, params Object[] args) { bool entered = false; try { m_lock.Enter(ref entered); sb.AppendFormat(fmt, args); return this; } finally { if (entered) m_lock.Exit(); } } public override String ToString() { bool entered = false; try { m_lock.Enter(ref entered); return sb.ToString(); } finally { if (entered) m_lock.Exit(); } } public int Length { get { bool entered = false; try { m_lock.Enter(ref entered); return sb.Length; } finally { if (entered) m_lock.Exit(); } } set { bool entered = false; try { m_lock.Enter(ref entered); sb.Length = value; } finally { if (entered) m_lock.Exit(); } } } }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public abstract class ConcurrentContainer<T> : ISet<T> { public abstract bool Add(T item); public abstract void Clear(); public abstract bool Contains(T item); public abstract int Count { get; } public abstract bool Remove(T item); public virtual IEnumerator<T> GetEnumerator() { throw new NotImplementedException(); } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return GetEnumerator(); } void ICollection<T>.Add(T item) { Add(item); } public bool IsReadOnly { get { return false; } } public void CopyTo(T[] array, int arrayIndex) { throw new NotSupportedException(); } public void ExceptWith(IEnumerable<T> other) { throw new NotSupportedException(); } public void IntersectWith(IEnumerable<T> other) { throw new NotSupportedException(); } public bool IsProperSubsetOf(IEnumerable<T> other) { throw new NotSupportedException(); } public bool IsProperSupersetOf(IEnumerable<T> other) { throw new NotSupportedException(); } public bool IsSubsetOf(IEnumerable<T> other) { throw new NotSupportedException(); } public bool IsSupersetOf(IEnumerable<T> other) { throw new NotSupportedException(); } public bool Overlaps(IEnumerable<T> other) { throw new NotSupportedException(); } public bool SetEquals(IEnumerable<T> other) { throw new NotSupportedException(); } public void SymmetricExceptWith(IEnumerable<T> other) { throw new NotSupportedException(); } public void UnionWith(IEnumerable<T> other) { throw new NotSupportedException(); } }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public class ConcurrentSymmetricDictionary<K1, K2> { SpinLock slock = new SpinLock(false); // do not make this 'readonly' Dictionary<K1, K2> forward; Dictionary<K2, K1> reverse; public ConcurrentSymmetricDictionary(IEqualityComparer<K1> c) { forward = new Dictionary<K1, K2>(c); reverse = new Dictionary<K2, K1>(); } public ConcurrentSymmetricDictionary(IEqualityComparer<K2> c) { forward = new Dictionary<K1, K2>(); reverse = new Dictionary<K2, K1>(c); } public ConcurrentSymmetricDictionary() { forward = new Dictionary<K1, K2>(); reverse = new Dictionary<K2, K1>(); } public K2 this[K1 k1] { get { return forward[k1]; } set { bool _b = false; try { slock.Enter(ref _b); forward[k1] = value; reverse[value] = k1; } finally { if (_b) slock.Exit(); } } } public K1 this[K2 k2] { get { return reverse[k2]; } set { bool _b = false; try { slock.Enter(ref _b); reverse[k2] = value; forward[value] = k2; } finally { if (_b) slock.Exit(); } } } public void Add(K1 k1, K2 k2) { bool _b = false; try { slock.Enter(ref _b); forward.Add(k1, k2); reverse.Add(k2, k1); } finally { if (_b) slock.Exit(); } } public bool Remove(K1 k1) { bool _b = false; try { slock.Enter(ref _b); K2 k2; if (!forward.TryGetValue(k1, out k2)) return false; forward.Remove(k1); reverse.Remove(k2); return true; } finally { if (_b) slock.Exit(); } } public bool Remove(K2 k2) { bool _b = false; try { slock.Enter(ref _b); K1 k1; if (!reverse.TryGetValue(k2, out k1)) return false; reverse.Remove(k2); forward.Remove(k1); } finally { if (_b) slock.Exit(); } return true; } public void Clear() { bool _b = false; try { slock.Enter(ref _b); forward.Clear(); reverse.Clear(); } finally { if (_b) slock.Exit(); } } public bool TryGetValue(K2 k2, out K1 k1) { return reverse.TryGetValue(k2, out k1); } public bool TryGetValue(K1 k1, out K2 k2) { return forward.TryGetValue(k1, out k2); } public K2 GetOrAdd(K1 k1, K2 k2) { bool _b = false; try { slock.Enter(ref _b); K2 v; if (!forward.TryGetValue(k1, out v)) { v = k2; forward.Add(k1, v); reverse.Add(v, k1); } return v; } finally { if (_b) slock.Exit(); } } }; }