亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > C# > 正文

深入線程安全容器的實現方法

2020-01-24 03:21:50
字體:
來源:轉載
供稿:網友

最近寫了個小程序用到了C#4.0中的線程安全集合。想起很久以前用C#2.0開發的時候寫后臺windows服務,為了利用多線程實現生產者和消費者模型,經常要封裝一些線程安全的容器,比如泛型隊列和字典等等。下面就結合部分MS的源碼和自己的開發經驗淺顯地分析一下如何實現線程安全容器以及實現線程安全容器容易產生的問題。

一、ArrayList

在C#早期版本中已經實現了線程安全的ArrayList,可以通過下面的方式構造線程安全的數組列表:

var array = ArrayList.Synchronized(new ArrayList());

我們從Synchronized方法入手,分析它的源代碼看是如何實現線程安全的:

復制代碼 代碼如下:

Synchronized        /// <summary>Returns an <see cref="T:System.Collections.ArrayList" /> wrapper that is synchronized (thread safe).</summary>
        /// <returns>An <see cref="T:System.Collections.ArrayList" /> wrapper that is synchronized (thread safe).</returns>
        /// <param name="list">The <see cref="T:System.Collections.ArrayList" /> to synchronize. </param>
        /// <exception cref="T:System.ArgumentNullException">
        ///   <paramref name="list" /> is null. </exception>
        /// <filterpriority>2</filterpriority>
        [HostProtection(SecurityAction.LinkDemand, Synchronization = true)]
        public static ArrayList Synchronized(ArrayList list)
        {
            if (list == null)
            {
                throw new ArgumentNullException("list");
            }
            return new ArrayList.SyncArrayList(list);
        }


繼續跟進去,發現SyncArrayList是一個繼承自ArrayList的私有類,內部線程安全方法的實現經過分析,很多都是像下面這樣lock(注意是lock_root對象而不是數組列表實例對象)一下完事:

lock (this._root)

有心的你可以查看SyncArrayList的源碼:

復制代碼 代碼如下:

SyncArrayList        [Serializable]
        private class SyncArrayList : ArrayList
        {
            private ArrayList _list;
            private object _root;
            public override int Capacity
            {
                get
                {
                    int capacity;
                    lock (this._root)
                    {
                        capacity = this._list.Capacity;
                    }
                    return capacity;
                }
                set
                {
                    lock (this._root)
                    {
                        this._list.Capacity = value;
                    }
                }
            }
            public override int Count
            {
                get
                {
                    int count;
                    lock (this._root)
                    {
                        count = this._list.Count;
                    }
                    return count;
                }
            }
            public override bool IsReadOnly
            {
                get
                {
                    return this._list.IsReadOnly;
                }
            }
            public override bool IsFixedSize
            {
                get
                {
                    return this._list.IsFixedSize;
                }
            }
            public override bool IsSynchronized
            {
                get
                {
                    return true;
                }
            }
            public override object this[int index]
            {
                get
                {
                    object result;
                    lock (this._root)
                    {
                        result = this._list[index];
                    }
                    return result;
                }
                set
                {
                    lock (this._root)
                    {
                        this._list[index] = value;
                    }
                }
            }
            public override object SyncRoot
            {
                get
                {
                    return this._root;
                }
            }
            internal SyncArrayList(ArrayList list)
                : base(false)
            {
                this._list = list;
                this._root = list.SyncRoot;
            }
            public override int Add(object value)
            {
                int result;
                lock (this._root)
                {
                    result = this._list.Add(value);
                }
                return result;
            }
            public override void AddRange(ICollection c)
            {
                lock (this._root)
                {
                    this._list.AddRange(c);
                }
            }
            public override int BinarySearch(object value)
            {
                int result;
                lock (this._root)
                {
                    result = this._list.BinarySearch(value);
                }
                return result;
            }
            public override int BinarySearch(object value, IComparer comparer)
            {
                int result;
                lock (this._root)
                {
                    result = this._list.BinarySearch(value, comparer);
                }
                return result;
            }
            public override int BinarySearch(int index, int count, object value, IComparer comparer)
            {
                int result;
                lock (this._root)
                {
                    result = this._list.BinarySearch(index, count, value, comparer);
                }
                return result;
            }
            public override void Clear()
            {
                lock (this._root)
                {
                    this._list.Clear();
                }
            }
            public override object Clone()
            {
                object result;
                lock (this._root)
                {
                    result = new ArrayList.SyncArrayList((ArrayList)this._list.Clone());
                }
                return result;
            }
            public override bool Contains(object item)
            {
                bool result;
                lock (this._root)
                {
                    result = this._list.Contains(item);
                }
                return result;
            }
            public override void CopyTo(Array array)
            {
                lock (this._root)
                {
                    this._list.CopyTo(array);
                }
            }
            public override void CopyTo(Array array, int index)
            {
                lock (this._root)
                {
                    this._list.CopyTo(array, index);
                }
            }
            public override void CopyTo(int index, Array array, int arrayIndex, int count)
            {
                lock (this._root)
                {
                    this._list.CopyTo(index, array, arrayIndex, count);
                }
            }
            public override IEnumerator GetEnumerator()
            {
                IEnumerator enumerator;
                lock (this._root)
                {
                    enumerator = this._list.GetEnumerator();
                }
                return enumerator;
            }
            public override IEnumerator GetEnumerator(int index, int count)
            {
                IEnumerator enumerator;
                lock (this._root)
                {
                    enumerator = this._list.GetEnumerator(index, count);
                }
                return enumerator;
            }
            public override int IndexOf(object value)
            {
                int result;
                lock (this._root)
                {
                    result = this._list.IndexOf(value);
                }
                return result;
            }
            public override int IndexOf(object value, int startIndex)
            {
                int result;
                lock (this._root)
                {
                    result = this._list.IndexOf(value, startIndex);
                }
                return result;
            }
            public override int IndexOf(object value, int startIndex, int count)
            {
                int result;
                lock (this._root)
                {
                    result = this._list.IndexOf(value, startIndex, count);
                }
                return result;
            }
            public override void Insert(int index, object value)
            {
                lock (this._root)
                {
                    this._list.Insert(index, value);
                }
            }
            public override void InsertRange(int index, ICollection c)
            {
                lock (this._root)
                {
                    this._list.InsertRange(index, c);
                }
            }
            public override int LastIndexOf(object value)
            {
                int result;
                lock (this._root)
                {
                    result = this._list.LastIndexOf(value);
                }
                return result;
            }
            public override int LastIndexOf(object value, int startIndex)
            {
                int result;
                lock (this._root)
                {
                    result = this._list.LastIndexOf(value, startIndex);
                }
                return result;
            }
            public override int LastIndexOf(object value, int startIndex, int count)
            {
                int result;
                lock (this._root)
                {
                    result = this._list.LastIndexOf(value, startIndex, count);
                }
                return result;
            }
            public override void Remove(object value)
            {
                lock (this._root)
                {
                    this._list.Remove(value);
                }
            }
            public override void RemoveAt(int index)
            {
                lock (this._root)
                {
                    this._list.RemoveAt(index);
                }
            }
            public override void RemoveRange(int index, int count)
            {
                lock (this._root)
                {
                    this._list.RemoveRange(index, count);
                }
            }
            public override void Reverse(int index, int count)
            {
                lock (this._root)
                {
                    this._list.Reverse(index, count);
                }
            }
            public override void SetRange(int index, ICollection c)
            {
                lock (this._root)
                {
                    this._list.SetRange(index, c);
                }
            }
            public override ArrayList GetRange(int index, int count)
            {
                ArrayList range;
                lock (this._root)
                {
                    range = this._list.GetRange(index, count);
                }
                return range;
            }
            public override void Sort()
            {
                lock (this._root)
                {
                    this._list.Sort();
                }
            }
            public override void Sort(IComparer comparer)
            {
                lock (this._root)
                {
                    this._list.Sort(comparer);
                }
            }
            public override void Sort(int index, int count, IComparer comparer)
            {
                lock (this._root)
                {
                    this._list.Sort(index, count, comparer);
                }
            }
            public override object[] ToArray()
            {
                object[] result;
                lock (this._root)
                {
                    result = this._list.ToArray();
                }
                return result;
            }
            public override Array ToArray(Type type)
            {
                Array result;
                lock (this._root)
                {
                    result = this._list.ToArray(type);
                }
                return result;
            }
            public override void TrimToSize()
            {
                lock (this._root)
                {
                    this._list.TrimToSize();
                }
            }
        }


ArrayList線程安全實現過程小結:定義ArrayList的私有實現SyncArrayList,子類內部通過lock同步構造實現線程安全,在ArrayList中通過Synchronized對外間接調用子類。 

二、Hashtable

同樣,在C#早期版本中實現了線程安全的Hashtable,它也是早期開發中經常用到的緩存容器,可以通過下面的方式構造線程安全的哈希表:

var ht = Hashtable.Synchronized(new Hashtable());

同樣地,我們從Synchronized方法入手,分析它的源代碼看是如何實現線程安全的:

復制代碼 代碼如下:

Synchronized        /// <summary>Returns a synchronized (thread-safe) wrapper for the <see cref="T:System.Collections.Hashtable" />.</summary>
        /// <returns>A synchronized (thread-safe) wrapper for the <see cref="T:System.Collections.Hashtable" />.</returns>
        /// <param name="table">The <see cref="T:System.Collections.Hashtable" /> to synchronize. </param>
        /// <exception cref="T:System.ArgumentNullException">
        ///   <paramref name="table" /> is null. </exception>
        /// <filterpriority>1</filterpriority>
        [HostProtection(SecurityAction.LinkDemand, Synchronization = true)]
        public static Hashtable Synchronized(Hashtable table)
        {
            if (table == null)
            {
                throw new ArgumentNullException("table");
            }
            return new Hashtable.SyncHashtable(table);
        }

繼續跟進去,發現SyncHashtable是一個繼承自Hashtable和IEnumerable接口的私有類,內部線程安全方法的實現經過分析,很多都是像下面這樣lock(注意是lock哈希表的SyncRoot Object實例對象而不是哈希表實例)一下完事:

lock (this._table.SyncRoot)

貼一下SyncHashtable的源碼:

復制代碼 代碼如下:

 [Serializable]
        private class SyncHashtable : Hashtable, IEnumerable
        {
            protected Hashtable _table;
            public override int Count
            {
                get
                {
                    return this._table.Count;
                }
            }
            public override bool IsReadOnly
            {
                get
                {
                    return this._table.IsReadOnly;
                }
            }
            public override bool IsFixedSize
            {
                get
                {
                    return this._table.IsFixedSize;
                }
            }
            public override bool IsSynchronized
            {
                get
                {
                    return true;
                }
            }
            public override object this[object key]
            {
                [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
                get
                {
                    return this._table[key];
                }
                set
                {
                    lock (this._table.SyncRoot)
                    {
                        this._table[key] = value;
                    }
                }
            }
            public override object SyncRoot
            {
                get
                {
                    return this._table.SyncRoot;
                }
            }
            public override ICollection Keys
            {
                get
                {
                    ICollection keys;
                    lock (this._table.SyncRoot)
                    {
                        keys = this._table.Keys;
                    }
                    return keys;
                }
            }
            public override ICollection Values
            {
                get
                {
                    ICollection values;
                    lock (this._table.SyncRoot)
                    {
                        values = this._table.Values;
                    }
                    return values;
                }
            }
            internal SyncHashtable(Hashtable table)
                : base(false)
            {
                this._table = table;
            }
            internal SyncHashtable(SerializationInfo info, StreamingContext context)
                : base(info, context)
            {
                this._table = (Hashtable)info.GetValue("ParentTable", typeof(Hashtable));
                if (this._table == null)
                {
                    throw new SerializationException(Environment.GetResourceString("Serialization_InsufficientState"));
                }
            }
            [SecurityCritical]
            public override void GetObjectData(SerializationInfo info, StreamingContext context)
            {
                if (info == null)
                {
                    throw new ArgumentNullException("info");
                }
                lock (this._table.SyncRoot)
                {
                    info.AddValue("ParentTable", this._table, typeof(Hashtable));
                }
            }
            public override void Add(object key, object value)
            {
                lock (this._table.SyncRoot)
                {
                    this._table.Add(key, value);
                }
            }
            public override void Clear()
            {
                lock (this._table.SyncRoot)
                {
                    this._table.Clear();
                }
            }
            [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
            public override bool Contains(object key)
            {
                return this._table.Contains(key);
            }
            [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
            public override bool ContainsKey(object key)
            {
                return this._table.ContainsKey(key);
            }
            public override bool ContainsValue(object key)
            {
                bool result;
                lock (this._table.SyncRoot)
                {
                    result = this._table.ContainsValue(key);
                }
                return result;
            }
            public override void CopyTo(Array array, int arrayIndex)
            {
                lock (this._table.SyncRoot)
                {
                    this._table.CopyTo(array, arrayIndex);
                }
            }
            public override object Clone()
            {
                object result;
                lock (this._table.SyncRoot)
                {
                    result = Hashtable.Synchronized((Hashtable)this._table.Clone());
                }
                return result;
            }
            IEnumerator IEnumerable.GetEnumerator()
            {
                return this._table.GetEnumerator();
            }
            public override IDictionaryEnumerator GetEnumerator()
            {
                return this._table.GetEnumerator();
            }
            public override void Remove(object key)
            {
                lock (this._table.SyncRoot)
                {
                    this._table.Remove(key);
                }
            }
            public override void OnDeserialization(object sender)
            {
            }
            internal override KeyValuePairs[] ToKeyValuePairsArray()
            {
                return this._table.ToKeyValuePairsArray();
            }
        }


Hashtable線程安全實現過程小結:定義Hashtable的私有實現SyncHashtable,子類內部通過lock同步構造實現線程安全,在Hashtable中通過Synchronized對外間接調用子類。

三、4.0中的線程安全容器

1、ConcurrentQueue

從上面的實現分析來說,封裝一個線程安全的容器看起來并不是什么難事,除了對線程安全容器的異常處理心有余悸,其他的似乎按步就班就可以了,不是嗎?也許還有更高明的實現吧?

在4.0中,多了一個System.Collections.Concurrent命名空間,懷著忐忑的心情查看C#4.0其中的一個線程安全集合ConcurrentQueue的源碼,發現它繼承自IProducerConsumerCollection<T>, IEnumerable<T>, ICollection, IEnumerable接口,內部實現線程安全的時候,通過SpinWait和通過互鎖構造(Interlocked)及SpinWait封裝的Segment,間接實現了線程安全。Segment的實現比較復雜,和線程安全密切相關的方法就是TryXXX那幾個方法,源碼如下:

復制代碼 代碼如下:

      private class Segment
        {
            internal T[] m_array;
            private int[] m_state;
            private ConcurrentQueue<T>.Segment m_next;
            internal readonly long m_index;
            private int m_low;
            private int m_high;
            internal ConcurrentQueue<T>.Segment Next
            {
                get
                {
                    return this.m_next;
                }
            }
            internal bool IsEmpty
            {
                get
                {
                    return this.Low > this.High;
                }
            }
            internal int Low
            {
                get
                {
                    return Math.Min(this.m_low, 32);
                }
            }
            internal int High
            {
                get
                {
                    return Math.Min(this.m_high, 31);
                }
            }
            internal Segment(long index)
            {
                this.m_array = new T[32];
                this.m_state = new int[32];
                this.m_high = -1;
                this.m_index = index;
            }
            internal void UnsafeAdd(T value)
            {
                this.m_high++;
                this.m_array[this.m_high] = value;
                this.m_state[this.m_high] = 1;
            }
            internal ConcurrentQueue<T>.Segment UnsafeGrow()
            {
                ConcurrentQueue<T>.Segment segment = new ConcurrentQueue<T>.Segment(this.m_index + 1L);
                this.m_next = segment;
                return segment;
            }
            internal void Grow(ref ConcurrentQueue<T>.Segment tail)
            {
                ConcurrentQueue<T>.Segment next = new ConcurrentQueue<T>.Segment(this.m_index + 1L);
                this.m_next = next;
                tail = this.m_next;
            }
            internal bool TryAppend(T value, ref ConcurrentQueue<T>.Segment tail)
            {
                if (this.m_high >= 31)
                {
                    return false;
                }
                int num = 32;
                try
                {
                }
                finally
                {
                    num = Interlocked.Increment(ref this.m_high);
                    if (num <= 31)
                    {
                        this.m_array[num] = value;
                        this.m_state[num] = 1;
                    }
                    if (num == 31)
                    {
                        this.Grow(ref tail);
                    }
                }
                return num <= 31;
            }
            internal bool TryRemove(out T result, ref ConcurrentQueue<T>.Segment head)
            {
                SpinWait spinWait = default(SpinWait);
                int i = this.Low;
                int high = this.High;
                while (i <= high)
                {
                    if (Interlocked.CompareExchange(ref this.m_low, i + 1, i) == i)
                    {
                        SpinWait spinWait2 = default(SpinWait);
                        while (this.m_state[i] == 0)
                        {
                            spinWait2.SpinOnce();
                        }
                        result = this.m_array[i];
                        if (i + 1 >= 32)
                        {
                            spinWait2 = default(SpinWait);
                            while (this.m_next == null)
                            {
                                spinWait2.SpinOnce();
                            }
                            head = this.m_next;
                        }
                        return true;
                    }
                    spinWait.SpinOnce();
                    i = this.Low;
                    high = this.High;
                }
                result = default(T);
                return false;
            }
            internal bool TryPeek(out T result)
            {
                result = default(T);
                int low = this.Low;
                if (low > this.High)
                {
                    return false;
                }
                SpinWait spinWait = default(SpinWait);
                while (this.m_state[low] == 0)
                {
                    spinWait.SpinOnce();
                }
                result = this.m_array[low];
                return true;
            }
            internal List<T> ToList(int start, int end)
            {
                List<T> list = new List<T>();
                for (int i = start; i <= end; i++)
                {
                    SpinWait spinWait = default(SpinWait);
                    while (this.m_state[i] == 0)
                    {
                        spinWait.SpinOnce();
                    }
                    list.Add(this.m_array[i]);
                }
                return list;
            }
        }


上面的代碼稍微分析一下就知道它的作用。ConcurrentQueue的線程安全的Enqueue方法實現如下:
復制代碼 代碼如下:

        /// <summary>Adds an object to the end of the <see cref="T:System.Collections.Concurrent.ConcurrentQueue`1" />.</summary>
        /// <param name="item">The object to add to the end of the <see cref="T:System.Collections.Concurrent.ConcurrentQueue`1" />. The value can be a null reference (Nothing in Visual Basic) for reference types.</param>
        public void Enqueue(T item)
        {
            SpinWait spinWait = default(SpinWait);
            while (true)
            {
                ConcurrentQueue<T>.Segment tail = this.m_tail;
                if (tail.TryAppend(item, ref this.m_tail))
                {
                    break;
                }
                spinWait.SpinOnce();
            }
        }

ConcurrentQueue<T>線程安全實現過程小結:繼承接口,子類內部通過同步構造實現接口的線程安全,直接對外公開調用。

和ArrayList以及Hashtable線程安全的“曲折”實現有點不同,ConcurrentQueue<T>一開始就是朝著線程安全方向實現去的。它沒有使用lock,因為大家知道使用lock性能略差,對于讀和寫操作,應該分開,不能一概而論。ConcurrentQueue<T>具體實現在性能和異常處理上應該已經考慮的更全面周到一點。

在我看來,ConcurrentQueue<T>線程安全的具體實現有多吸引人在其次,IProducerConsumerCollection<T>接口的抽象和提取非常值得稱道,查看源碼發現ConcurrentStack<T>和ConcurrentBag<T>也繼承自該接口。<<CLR via C#>>一書中在談到接口和抽象類的時候特別舉了集合和流(Stream)的例子,微軟為什么如此設計,想起來果然很有深意。

復制代碼 代碼如下:

      public bool TryAdd(TKey key, TValue value)
        {
            if (key == null)
            {
                throw new ArgumentNullException("key");
            }
            TValue tValue;
            return this.TryAddInternal(key, value, false, true, out tValue);
        }

其中內部方法TryAdd的主要實現如下:
復制代碼 代碼如下:

private bool TryAddInternal(TKey key, TValue value, bool updateIfExists, bool acquireLock, out TValue resultingValue)
        {
            checked
            {
                int hashCode = this.m_comparer.GetHashCode(key);
                ConcurrentDictionary<TKey, TValue>.Node[] buckets;
                bool flag;
                bool result;
                while (true)
                {
                    buckets = this.m_buckets;
                    int num;
                    int num2;
                    this.GetBucketAndLockNo(hashCode, out num, out num2, buckets.Length);
                    flag = false;
                    bool flag2 = false;
                    try
                    {
                        if (acquireLock)
                        {
                            Monitor.Enter(this.m_locks[num2], ref flag2);
                        }
                        if (buckets != this.m_buckets)
                        {
                            continue;
                        }
                        ConcurrentDictionary<TKey, TValue>.Node node = null;
                        for (ConcurrentDictionary<TKey, TValue>.Node node2 = buckets[num]; node2 != null; node2 = node2.m_next)
                        {
                            if (this.m_comparer.Equals(node2.m_key, key))
                            {
                                if (updateIfExists)
                                {
                                    ConcurrentDictionary<TKey, TValue>.Node node3 = new ConcurrentDictionary<TKey, TValue>.Node(node2.m_key, value, hashCode, node2.m_next);
                                    if (node == null)
                                    {
                                        buckets[num] = node3;
                                    }
                                    else
                                    {
                                        node.m_next = node3;
                                    }
                                    resultingValue = value;
                                }
                                else
                                {
                                    resultingValue = node2.m_value;
                                }
                                result = false;
                                return result;
                            }
                            node = node2;
                        }
                        buckets[num] = new ConcurrentDictionary<TKey, TValue>.Node(key, value, hashCode, buckets[num]);
                        this.m_countPerLock[num2]++;
                        if (this.m_countPerLock[num2] > buckets.Length / this.m_locks.Length)
                        {
                            flag = true;
                        }
                    }
                    finally
                    {
                        if (flag2)
                        {
                            Monitor.Exit(this.m_locks[num2]);
                        }
                    }
                    break;
                }
                if (flag)
                {
                    this.GrowTable(buckets);
                    goto IL_131;
                }
                goto IL_131;
                return result;
            IL_131:
                resultingValue = value;
                return true;
            }
        }


同步構造Monitor瞬間吸引眼球,然后它的try…finally異常處理方式是不是也很眼熟?


 

 

2、ConcurrentDictionary<TKey, TValue>

對于線程安全的泛型字典ConcurrentDictionary<TKey, TValue>,我們也可以查看它的源碼看它的具體實現方式??丛创a有1200多行,實現稍微復雜一些。我們僅從最簡單的TryAdd方法分析:

四、如法炮制

如果讓我來構造實現線程安全容器,最簡單直接快速高效的方式就是參考ArrayList和 Hashtable,我們完全可以模仿它們的處理方式,通過繼承一個容器,然后內部通過lock一個SyncRoot對象,中規中矩地實現framework中其他容器的線程安全。比如要實現線程安全的泛型隊列Queue<T>,貼一下大致的偽代碼

復制代碼 代碼如下:

  private class SyncQueue<T> : Queue<T>
    {
        #region fields and properties

        private Queue<T> queue = null;
        private object syncRoot = null;
        internal object SyncRoot
        {
            get
            {
                return syncRoot;
            }
        }

        #endregion

        #region constructors

        public SyncQueue()
        {
            syncRoot = new object();
            queue = new Queue<T>();
        }

        public SyncQueue(IEnumerable<T> collection)
        {
            syncRoot = new object();
            queue = new Queue<T>(collection);
        }

        public SyncQueue(int capacity)
        {
            syncRoot = new object();
            queue = new Queue<T>(capacity);
        }

        #endregion

        #region methods

        public new void Enqueue(T item)
        {
            lock (SyncRoot)
            {
                this.Enqueue(item);
            }
        }

        public new T Dequeue()
        {
            T result = default(T);
            lock (SyncRoot)
            {
                result = this.queue.Dequeue();
            }
            return result;
        }

        public new void Clear()
        {
            lock (SyncRoot)
            {
                this.queue.Clear();
            }
        }

        public new bool Contains(T item)
        {
            var exists = false;
            lock (SyncRoot)
            {
                exists = this.queue.Contains(item);
            }
            return exists;
        }

        #endregion

    }


通過類繼承我們可以得到泛型隊列的所有特點,需要實現線程安全的地方只要按需重寫它即可,對外調用也很簡單,直接模仿ArrayList和Hashtable,添加Synchronized方法間接調用隊列的子類即可,多么清晰簡潔啊,關鍵時刻copy-paste也很有效嘛!

你可能覺得上面這樣不動腦的方式似乎很傻很天真,但這絕對是一種正常人都能想到的思路,誰讓MS的數組列表和哈希表就是這么實現的呢?

當然,我們還能想到的一種常見實現方式就是通過組合而不是類繼承,實現的偽代碼類似下面這樣:

復制代碼 代碼如下:

public class SyncQueue<T>
    {
        #region fields and properties

        private Queue<T> queue = null;
        private object syncRoot = null;
        internal object SyncRoot
        {
            get
            {
                return syncRoot;
            }
        }

        #endregion

        #region constructors

        public SyncQueue()
        {
            syncRoot = new object();
            queue = new Queue<T>();
        }

        public SyncQueue(IEnumerable<T> collection)
        {
            syncRoot = new object();
            queue = new Queue<T>(collection);
        }

        public SyncQueue(int capacity)
        {
            syncRoot = new object();
            queue = new Queue<T>(capacity);
        }

        #endregion

        #region methods

        public void Enqueue(T item)
        {
            lock (SyncRoot)
            {
                this.Enqueue(item);
            }
        }

        public T Dequeue()
        {
            T result = default(T);
            lock (SyncRoot)
            {
                result = this.queue.Dequeue();
            }
            return result;
        }

        public void Clear()
        {
            lock (SyncRoot)
            {
                this.queue.Clear();
            }
        }

        public bool Contains(T item)
        {
            var exists = false;
            lock (SyncRoot)
            {
                exists = this.queue.Contains(item);
            }
            return exists;
        }

        #endregion

    }


上面這種方式和類繼承的實現方式又有不同。它是通過在內部包裝一個容器,然后按需進行方法、屬性等等的線程安全處理,其他的所有特點依賴于那一個私有泛型隊列組合對象queue。這種情況下泛型SyncQueue和泛型隊列是組合關系,依賴性和耦合性更低,相對更靈活,封裝性更好,是一種較為通用的設計,實際開發和使用中這種方式比較常見。

到這里,我們至少可以分析得出,實現一般的線程安全容器的思路至少有兩種:類繼承(內部實現偏向使用組合)和(或)組合,線程安全的地方只要通過framework的同步構造如lock、Interlocked等實現即可。

思考:如果讓您實現線程安全容器,您優先會怎么實現呢?

五、線程安全并不真正安全

1、foreach遍歷

CacheUtil緩存實現的偽代碼如下:

復制代碼 代碼如下:

   public class CacheUtil
    {
        private static readonly Hashtable ht = Hashtable.Synchronized(new Hashtable());

        public static bool TryAdd(object key, object value)
        {
            ht[key] = value; //set方法是線程安全的
            return true;
        }

        public static bool TryGet(object key, out object result)
        {
            result = null;
            lock (ht.SyncRoot)
            {
                if (ht.ContainsKey(key))
                {
                    result = ht[key];
                }
            }
            return true;
        }
    }


foreach的代碼很簡單,從哈希表構造的緩存中取數據并遍歷,如下:
復制代碼 代碼如下:

          object obj = null;
            var isOK = CacheUtil.TryGet("key", out obj);
            if (isOK == false)
            {
                return;
            }
            var list = obj as IList<T>;
            if (list == null)
            {
                return;
            }
            foreach (var item in list) //遍歷
            {
                //do something
            }

上面的遍歷代碼一般情況下是不會有問題的。但是在多線程修改哈希表的Value的情況下,上面的foreach遍歷有可能發生異常。為什么呢?下面來簡單分析一下:

從代碼中可以看出來,哈希表中的Value存放的是IList類型,那么值所保存的應該是一個引用(也就是指針)。
(1)、當線程1通過索引器得到這個IList時,這個TryGet讀取操作是線程安全的。接著線程1進行的操作是列表遍歷。在foreach進行遍歷不為空的List的時候,遍歷的其實是存放在IList指針指向的引用。

(2)、在foreach遍歷集合的時候,這時候線程2如果正好對哈希表的key所對應的Value進行修改,IList的指針所指向的引用改變了,所以線程1的遍歷操作就會拋出異常。

這是一個簡單而又經典的陷阱,在哈希表的MSDN線程安全塊有一段說明:

Enumerating through a collection is intrinsically not a thread safe procedure. Even when a collection is synchronized, other threads can still modify the collection, which causes the enumerator to throw an exception. To guarantee thread safety during enumeration, you can either lock the collection during the entire enumeration or catch the exceptions resulting from changes made by other threads.

 

2、通過索引取集合中的數據

列表通過索引取值,一個簡單的示例代碼如下:

復制代碼 代碼如下:

        static int GetFirstOrDefault(ThreadSafeList<int> list)
        {
            if (list.Count > 0)
            {
                return list[0];
            }
            return 0;
        }

當列表中的元素為1個的時候,上面的操作非常容易進入一個無厘頭的陷阱之中。有人會問怎么會有陷阱,你看取數據之前都判斷了啊,邏輯正確了啊,這哪里還有問題嗎?

按照類似于1中的分析,GetFirstOrDefault應該可以分為下面兩步:

(1)線程1取數據,判斷list.Count的時候發現列表內有1個元素,這一步線程安全,沒有任何問題,然后準備返回索引為0的元素;

(2)線程2在線程1將要取索引為0的元素之前移除了列表中的唯一元素或者直接將list指向null,這樣線程1通過索引取元素就拋出異常了。

 

3、如何保證容器數據操作安全?

從上面的兩個示例,我們得知通常所看到的線程安全實際上并不一定安全。不安全的主要原因就是容器內的數據很容易被其他線程改變,或者可以簡要概括為:一段時間差引發的血案。實際上,我們平時所做的業務系統,歸根結底很多bug或者隱藏的缺陷都是由不起眼的一小段時間差引起的。

保證容器內的數據和操作都安全,一種簡單而有效的方法就是將你所要進行的操作進行“事務”處理。比如示例1中哈希表的Value的遍歷操作,通常情況下,我們分作兩步:

(1)、(安全地)讀取數據

(2)、(不安全地)遍歷;

為了達到遍歷操作不拋出異常,我們可以把兩步合并為一步,抽象出一個線程安全的新方法TryGetAndEnumerate,這樣可以保證線程安全地取數據和遍歷,具體實現無非是lock一下SyncRoot類似的這種思路。但是這種線程安全的遍歷可能代價很高,而且極其不通用。

線程安全集合容易產生的問題和解決方法,請參考JaredPar MSFT的Why are thread safe collections so hard?,這篇文章對設計一個線程安全的容器的指導原則是:

1、Don't add an decision procedures(procedures like Count as decision procedures).  They lead users down the path to bad code.
2、Methods which query the object can always fail and the API should reflect this.

實際上大家都知道利用事務處理思想多用TryXXX方法一般是沒錯的。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
韩国v欧美v日本v亚洲| 91九色国产视频| 亚洲精品视频网上网址在线观看| 亚洲精品美女视频| 日韩中文字幕在线播放| 色婷婷综合成人| 一区二区三区亚洲| 91精品国产九九九久久久亚洲| 中文字幕国产日韩| 久久天天躁狠狠躁老女人| 欧美日韩国产色视频| 国产成人极品视频| 久久精品国产成人| 久久久精品影院| 亚洲网址你懂得| 国产亚洲欧美视频| 国产日韩欧美影视| 亚洲欧美综合精品久久成人| 91极品女神在线| 欧美专区中文字幕| 亚洲精品乱码久久久久久按摩观| 欧美国产日韩xxxxx| 浅井舞香一区二区| 亚洲精品视频在线播放| 日韩欧美综合在线视频| 欧美午夜激情视频| 粉嫩老牛aⅴ一区二区三区| 不卡av在线播放| 欧美另类精品xxxx孕妇| 日韩av在线直播| 69av在线视频| 亚洲人成啪啪网站| 成人福利网站在线观看11| 欧美一区二粉嫩精品国产一线天| 综合136福利视频在线| 91国产精品91| 色综合久久88色综合天天看泰| 欧美激情精品久久久久| 在线激情影院一区| 色综合老司机第九色激情| 久热国产精品视频| 国产精品美女视频网站| 亚洲激情久久久| 久久久久久久久久久久av| 国产精品盗摄久久久| 欧美日韩在线另类| 91麻豆国产精品| 色综合色综合久久综合频道88| 欧美性猛交xxxx富婆| 国产精品美女网站| 亚洲激情视频在线| 久久精品国产亚洲精品| 91亚洲va在线va天堂va国| 91综合免费在线| 亚洲va久久久噜噜噜久久天堂| 欧美中文在线观看国产| 欧美有码在线观看| 九九九久久久久久| 午夜精品久久久久久久久久久久久| 亚洲免费视频在线观看| 大桥未久av一区二区三区| 97婷婷涩涩精品一区| 亚洲美女中文字幕| 欧美一乱一性一交一视频| 国产婷婷色综合av蜜臀av| 久久久久久成人精品| 最新的欧美黄色| 久久久久久久激情视频| 成人写真福利网| 亚洲人成网站色ww在线| 96精品久久久久中文字幕| 精品久久久一区| 亚洲毛茸茸少妇高潮呻吟| 久久久成人的性感天堂| 亚洲欧洲成视频免费观看| 日韩电影免费观看在线| 欧美高清在线观看| 日韩一级黄色av| 亚洲人成电影网站| 欧美亚洲成人网| 6080yy精品一区二区三区| 国产精品第8页| 亚洲人成电影在线观看天堂色| 亚洲护士老师的毛茸茸最新章节| 亚洲精品久久久久| 欧美日韩国产中文精品字幕自在自线| 日本不卡免费高清视频| 性欧美激情精品| 久久精品久久久久| 国产亚洲精品久久久久久| 日韩中文字在线| 黄色成人在线播放| 国产亚洲人成网站在线观看| 亚洲精品中文字| 亚洲欧美国产精品久久久久久久| 国产精品jizz在线观看麻豆| 欧美日韩一区二区在线播放| 国产精品三级在线| 欧美成人午夜激情视频| 一区二区三区www| 欧美激情一二区| 欧美日产国产成人免费图片| 九九综合九九综合| 91精品免费久久久久久久久| 亚洲成人免费网站| 亚洲国产欧美一区二区三区久久| 精品久久中文字幕久久av| 日韩精品视频在线| 日本一区二区在线免费播放| www.日本久久久久com.| 91国偷自产一区二区三区的观看方式| 一区二区三区无码高清视频| 日韩女优人人人人射在线视频| 91大神在线播放精品| 4438全国亚洲精品在线观看视频| 欧美视频免费在线观看| 8x海外华人永久免费日韩内陆视频| 国产欧美韩国高清| 日韩av电影在线网| 日韩av在线影视| 国产中文字幕亚洲| 欧美精品激情在线观看| 欧美电影电视剧在线观看| 2019最新中文字幕| 久久久久国产精品免费| 久久久精品免费视频| 欧美激情一级精品国产| 茄子视频成人在线| 91av网站在线播放| 69av在线播放| 成人国产在线视频| 亚洲男人第一av网站| 精品国内亚洲在观看18黄| 欧美成人激情在线| 亚洲人精选亚洲人成在线| 久久久久国色av免费观看性色| 日韩精品中文字幕在线观看| 亚洲国产精品久久久久秋霞蜜臀| 国产精品看片资源| 2021久久精品国产99国产精品| 久久影视三级福利片| 亚洲国产成人在线视频| 91久久在线视频| 日韩高清电影免费观看完整版| 欧美日韩国产第一页| 国产一区二区三区在线观看视频| 欧美精品videos性欧美| 性视频1819p久久| 欧美精品九九久久| 国产精品亚洲一区二区三区| 欧美日韩第一视频| 中国china体内裑精亚洲片| 成人av资源在线播放| 亚洲成人av资源网| 精品久久久久久久久国产字幕| 久久综合色88| 亲爱的老师9免费观看全集电视剧| 色哟哟入口国产精品| 日韩av电影在线免费播放| 国语自产精品视频在线看一大j8| 自拍偷拍免费精品| 国产男女猛烈无遮挡91| 亚洲一区二区三区xxx视频| 国产日韩中文字幕在线|