[. Net]: thread safe collection

Source: Internet
Author: User

 

Preface:

Recently, we were overwhelmed by sharing data sets for multi-thread programs.
The main problems are,
When a thread uses foreach to list data sets, the other thread changes the data set.
In this case, an exception occurs, indicating that the data set is changed while listing.

The first solution that comes to mind is to use lock to lock the set of read and write data.
This can indeed solve the problem,
However, no matter whether the read/write operations are performed, the lock will reduce the execution efficiency of the program.
In this way, you must remember to lock the code of the program that uses the data set. Otherwise, an error will occur.

 

I found this article "talking about program multitasking (III)-execution thread security and data collection" online, which just solved my problem. : D

The main idea of this article is,
Use readerwriterlockslim to create the ienumerable and ienumerator interfaces to encapsulate the lock action.
Read-Only locks are used to read and list data sets.
When writing data sets, write locks and read-only locks are not allowed.

A Data Set created in this way,
In terms of appearance, because the ienumerable and ienumerator interfaces are established to encapsulate the lock action, you do not need to pay attention to the lock action when using the program code of the data set.
In addition, the read/write locks can achieve maximum efficiency in scenarios where a large amount of data is taken and a small amount of data is written.

 

This article develops a scalable thread safe collection based on the idea of "talking about Program Multi-task (III)-execution thread security and data collection.
Keep a record and hope to help developers with the same problems.

 

Program code:

Threadsafereaderwriterlock:
First, threadsafereaderwriterlock is set up to improve the dipose function of readerwriterlock.
Reference data: "talking about program multitasking (I) -- upgraded version of the data lock and wait mechanism 」

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading;namespace CLK.Threading{    public class ThreadSafeReaderWriterLock : IDisposable    {        // Fields        private readonly ReaderWriterLockSlim _readerWriterLock = new ReaderWriterLockSlim();        private readonly CountdownEvent _countdownEvent = new CountdownEvent(1);        // Constructor        public ThreadSafeReaderWriterLock()         {         }        public void Dispose()        {            _countdownEvent.Signal();            _countdownEvent.Wait();            _countdownEvent.Dispose();            _readerWriterLock.Dispose();        }                // Methods        public void EnterReadLock()        {            _countdownEvent.AddCount();            _readerWriterLock.EnterReadLock();        }        public void ExitReadLock()        {            _readerWriterLock.ExitReadLock();            _countdownEvent.Signal();        }        public void EnterWriteLock()        {            _countdownEvent.AddCount();            _readerWriterLock.EnterWriteLock();        }        public void ExitWriteLock()        {            _readerWriterLock.ExitWriteLock();            _countdownEvent.Signal();        }    }}

 

Threadsafeenumerator <t>:
Create threadsafeenumerator <t> to process the lock action that uses foeach for listing.

using System;using System.Collections.Generic;using System.Linq;using System.Text;using CLK.Threading;namespace CLK.Collections.Concurrent{    public sealed class ThreadSafeEnumerator<T> : IEnumerator<T>, IDisposable    {        // Fields                 private readonly ThreadSafeReaderWriterLock _readerWriterLock = null;        private readonly IEnumerator<T> _component = null;                private readonly object _syncRoot = new object();        private bool _disposed = false;        // Constructor        public ThreadSafeEnumerator(Func getEnumeratorDelegate, ThreadSafeReaderWriterLock readerWriterLock)        {            #region Require            if (getEnumeratorDelegate == null) throw new ArgumentNullException();            if (readerWriterLock == null) throw new ArgumentNullException();            #endregion            // ReaderWriterLock            _readerWriterLock = readerWriterLock;            _readerWriterLock.EnterReadLock();            // Component            _component = getEnumeratorDelegate();        }        public void Dispose()        {            // Require            lock (_syncRoot)            {                if (_disposed == true) return;                _disposed = true;            }            // Component            _component.Dispose();            // ReaderWriterLock                        _readerWriterLock.ExitReadLock();        }        // Properties        public T Current        {            get { return _component.Current; }        }        object System.Collections.IEnumerator.Current        {            get { return this.Current; }        }        // Methods        public bool MoveNext()        {            return _component.MoveNext();        }        public void Reset()        {            _component.Reset();        }    }}

 

Threadsafeenumerable <t>:
Create threadsafeenumerable <t> to process the read/write data lock action. It is also the basic object for subsequent Data Set expansion.

using System;using System.Collections;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading;using CLK.Threading;namespace CLK.Collections.Concurrent{    public class ThreadSafeEnumerable<T> : IEnumerable<T>, IDisposable    {        // Fields                 private readonly ThreadSafeReaderWriterLock _readerWriterLock = null;        private readonly IEnumerable<T> _component = null;               private readonly object _syncRoot = new object();        private bool _disposed = false;        // Constructor        protected ThreadSafeEnumerable(IEnumerable<T> component)        {            #region Require                       if (component == null) throw new ArgumentNullException();            #endregion            // ReaderWriterLock            _readerWriterLock = new ThreadSafeReaderWriterLock();            // Component            _component = component;                    }        public void Dispose()        {            // Require            lock (_syncRoot)            {                if (_disposed == true) return;                _disposed = true;            }            // ReaderWriterLock                        _readerWriterLock.Dispose();            // Component            if (_component is IDisposable)            {                ((IDisposable)_component).Dispose();            }        }        // Methods        protected void EnterReadLock()        {            _readerWriterLock.EnterReadLock();        }        protected void ExitReadLock()        {            _readerWriterLock.ExitReadLock();        }        protected void EnterWriteLock()        {            _readerWriterLock.EnterWriteLock();        }        protected void ExitWriteLock()        {            _readerWriterLock.ExitWriteLock();        }        public IEnumerator<T> GetEnumerator()        {            return new ThreadSafeEnumerator<T>(_component.GetEnumerator, _readerWriterLock);        }        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()        {            return this.GetEnumerator();        }    }}

 

Threadsafecollection <t>:
This is the first extended data set. It is based on threadsafeenumerable <t> and implements the icollection <t> interface function.
Note that the read/write dataset type uses different lock actions.

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.ComponentModel;using System.Threading;namespace CLK.Collections.Concurrent{    public class ThreadSafeCollection<T> : ThreadSafeEnumerable<T>, ICollection<T>    {        // Fields                 private readonly ICollection<T> _component = null;        // Constructor        public ThreadSafeCollection() : this(new List<T>()) { }        protected ThreadSafeCollection(ICollection<T> component) : base(component)        {            #region Require                       if (component == null) throw new ArgumentNullException();            #endregion            // Component            _component = component;                    }                // Properties        public int Count        {            get            {                try                {                    this.EnterReadLock();                    return _component.Count;                }                finally                {                    this.ExitReadLock();                }            }        }        public bool IsReadOnly        {            get            {                try                {                    this.EnterReadLock();                    return _component.IsReadOnly;                }                finally                {                    this.ExitReadLock();                }            }        }        // Methods        public void Add(T item)        {            try            {                this.EnterWriteLock();                _component.Add(item);            }            finally            {                this.ExitWriteLock();            }        }        public bool Remove(T item)        {            try            {                this.EnterWriteLock();                return _component.Remove(item);            }            finally            {                this.ExitWriteLock();            }        }        public void Clear()        {            try            {                this.EnterWriteLock();                _component.Clear();            }            finally            {                this.ExitWriteLock();            }        }               public bool Contains(T item)        {            try            {                this.EnterReadLock();                return _component.Contains(item);            }            finally            {                this.ExitReadLock();            }        }        public void CopyTo(T[] array, int arrayIndex)        {            try            {                this.EnterReadLock();                _component.CopyTo(array, arrayIndex);            }            finally            {                this.ExitReadLock();            }        }            }}

 

Threadsafelist <t>:
At last, a data set threadsafelist <t> is extended, which is based on threadsafecollection <t> and implements the ilist <t> interface function.

using System;using System.Collections.Generic;using System.Linq;using System.Text;namespace CLK.Collections.Concurrent{    public class ThreadSafeList<T> : ThreadSafeCollection<T>, IList<T>    {        // Fields                 private readonly IList<T> _component = null;        // Constructor        public ThreadSafeList() : this(new List<T>()) { }        protected ThreadSafeList(IList<T> component)            : base(component)        {            #region Require            if (component == null) throw new ArgumentNullException();            #endregion            // Component            _component = component;        }        // Properties        public T this[int index]        {            get            {                try                {                    this.EnterReadLock();                    return _component[index];                }                finally                {                    this.ExitReadLock();                }            }            set            {                try                {                    this.EnterWriteLock();                    _component[index] = value;                }                finally                {                    this.ExitWriteLock();                }            }        }        // Methods        public void Insert(int index, T item)        {            try            {                this.EnterWriteLock();                _component.Insert(index, item);            }            finally            {                this.ExitWriteLock();            }        }        public void RemoveAt(int index)        {            try            {                this.EnterWriteLock();                _component.RemoveAt(index);            }            finally            {                this.ExitWriteLock();            }        }        public int IndexOf(T item)        {            try            {                this.EnterReadLock();                return _component.IndexOf(item);            }            finally            {                this.ExitReadLock();            }        }    }}

 

Postscript:

According to the above method of extending the data set, various thread safe collections such as idictionary can be extended.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.