winform development USES the universal multithreaded base class to share of in queues

  • 2020-05-27 07:01:18
  • OfStack


/// <summary>
    ///  Queue multithreading ,T  Represents a single type of processing ~
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public abstract class QueueThreadBase<T>
    {
        #region  variable & attribute 
        /// <summary>
        ///  Pending result 
        /// </summary>
        private class PendingResult
        {
            /// <summary>
            ///  Value to be processed 
            /// </summary>
            public T PendingValue { get; set; }
            /// <summary>
            ///  If there is a value 
            /// </summary>
            public bool IsHad { get; set; }
        }
        /// <summary>
        ///  The number of threads 
        /// </summary>
        public int ThreadCount
        {
            get { return this.m_ThreadCount; }
            set { this.m_ThreadCount = value; }
        }
        private int m_ThreadCount = 5;
        /// <summary>
        ///  cancel =True
        /// </summary>
        public bool Cancel { get; set; }
        /// <summary>
        ///  The thread list 
        /// </summary>
        List<Thread> m_ThreadList;
        /// <summary>
        ///  Number of completion queues 
        /// </summary>
        private volatile int m_CompletedCount = 0;
        /// <summary>
        ///  The total number of queue 
        /// </summary>
        private int m_QueueCount = 0;
        /// <summary>
        ///  All complete lock 
        /// </summary>
        private object m_AllCompletedLock = new object();
        /// <summary>
        ///  Number of completed threads 
        /// </summary>
        private int m_CompetedCount = 0;
        /// <summary>
        ///  The queue lock 
        /// </summary>
        private object m_PendingQueueLock = new object();
        private Queue<T> m_InnerQueue;
        #endregion

        #region  Event correlation 
        /// <summary>
        ///  All complete events 
        /// </summary>
        public event Action<CompetedEventArgs> AllCompleted;
        /// <summary>
        ///  Single completion event 
        /// </summary>
        public event Action<T, CompetedEventArgs> OneCompleted;
        /// <summary>
        ///  Raises all completion events 
        /// </summary>
        /// <param name="args"></param>
        private void OnAllCompleted(CompetedEventArgs args)
        {
            if (AllCompleted != null)
            {
                try
                {
                    AllCompleted(args);// All complete events 
                }
                catch { }
            }
        }
        /// <summary>
        ///  Raises a single completion event 
        /// </summary>
        /// <param name="pendingValue"></param>
        /// <param name="args"></param>
        private void OnOneCompleted(T pendingValue, CompetedEventArgs args)
        {
            if (OneCompleted != null)
            {
                try
                {
                    OneCompleted(pendingValue, args);
                }
                catch { }
            }
        } 
        #endregion
        #region  structure 
        public QueueThreadBase(IEnumerable<T> collection)
        {
            m_InnerQueue = new Queue<T>(collection);
            this.m_QueueCount = m_InnerQueue.Count;
        }

        #endregion
        #region  The main body 
        /// <summary>
        ///  Initialization thread 
        /// </summary>
        private void InitThread()
        {
            m_ThreadList = new List<Thread>();
            for (int i = 0; i < ThreadCount; i++)
            {
                Thread t = new Thread(new ThreadStart(InnerDoWork));
        m_ThreadList.Add(t);
                t.IsBackground = true;
                t.Start();
            }
        }
        /// <summary>
        ///  start 
        /// </summary>
        public void Start()
        {
            InitThread();
        }
        /// <summary>
        ///  Thread work 
        /// </summary>
        private void InnerDoWork()
        {
            try
            {
                Exception doWorkEx = null;
                DoWorkResult doworkResult = DoWorkResult.ContinueThread;
                var t = CurrentPendingQueue;
                while (!this.Cancel && t.IsHad)
                {
                    try
                    {
                        doworkResult = DoWork(t.PendingValue);
                    }
                    catch (Exception ex)
                    {
                        doWorkEx = ex;
                    }
                    m_CompletedCount++;
                    int precent = m_CompletedCount * 100 / m_QueueCount;
                    OnOneCompleted(t.PendingValue, new CompetedEventArgs() { CompetedPrecent = precent, InnerException = doWorkEx });
                    if (doworkResult == DoWorkResult.AbortAllThread)
                    {
                        this.Cancel = true;
                        break;
                    }
                    else if (doworkResult == DoWorkResult.AbortCurrentThread)
                    {
                        break;
                    }
                    t = CurrentPendingQueue;
                }
                lock (m_AllCompletedLock)
                {
                    m_CompetedCount++;
                    if (m_CompetedCount == m_ThreadList.Count)
                    {
                        OnAllCompleted(new CompetedEventArgs() { CompetedPrecent = 100 });
                    }
                }
            }
            catch 
            {
                throw;
            }
        }
        /// <summary>
        ///  Subclasses override 
        /// </summary>
        /// <param name="pendingValue"></param>
        /// <returns></returns>
        protected virtual DoWorkResult DoWork(T pendingValue)
        {
            return DoWorkResult.ContinueThread;
        }
        /// <summary>
        ///  Get the current result 
        /// </summary>
        private PendingResult CurrentPendingQueue
        {
            get
            {
                lock (m_PendingQueueLock)
                {
                    PendingResult t = new PendingResult();
                    if (m_InnerQueue.Count != 0)
                    {
                        t.PendingValue = m_InnerQueue.Dequeue();
                        t.IsHad = true;
                    }
                    else
                    {
                        t.PendingValue = default(T);
                        t.IsHad = false;
                    }
                    return t;
                }
            }
        }

        #endregion
        #region  Related classes & The enumeration 
        /// <summary>
        /// dowork Results the enumeration 
        /// </summary>
        public enum DoWorkResult
        {
            /// <summary>
            ///  Continue running, default 
            /// </summary>
            ContinueThread = 0,
            /// <summary>
            ///  Terminate the current thread 
            /// </summary>
            AbortCurrentThread = 1,
            /// <summary>
            ///  Terminate all threads 
            /// </summary>
            AbortAllThread = 2
        }
        /// <summary>
        ///  Completion event data 
        /// </summary>
        public class CompetedEventArgs : EventArgs
        {
            public CompetedEventArgs()
            {
            }
            /// <summary>
            ///  Completion percentage 
            /// </summary>
            public int CompetedPrecent { get; set; }
            /// <summary>
            ///  Exception information 
            /// </summary>
            public Exception InnerException { get; set; }
        } 
        #endregion
    }

From the point of view of the constructor, it deals with a certain list. That's right. This multi-thread can only deal with a certain list. Would you like to ask if you can add 1 side and deal with 1 side? (hehe, can, please contact the building Lord, of course you also can write by yourself, right? !).


public QueueThreadBase(IEnumerable<T> collection)

2. Provide undo function


/// <summary>
        ///  cancel =True
        /// </summary>
        public bool Cancel { get; set; }

3. Provide the function of thread number modification


/// <summary>
        ///  The number of threads 
        /// </summary>
        public int ThreadCount
        {
            get { return this.m_ThreadCount; }
            set { this.m_ThreadCount = value; }
        }

4. Provide multiple event responses, such as single completed event, complete event


/// <summary>
        ///  All complete events 
        /// </summary>
        public event Action<CompetedEventArgs> AllCompleted;
        /// <summary>
        ///  Single completion event 
        /// </summary>
        public event Action<T, CompetedEventArgs> OneCompleted;

5. Provide a percentage of completion


/// <summary>
        ///  Completion event data 
        /// </summary>
        public class CompetedEventArgs : EventArgs
        {
            public CompetedEventArgs()
            {
            }
            /// <summary>
            ///  Completion percentage 
            /// </summary>
            public int CompetedPrecent { get; set; }
            /// <summary>
            ///  Exception information 
            /// </summary>
            public Exception InnerException { get; set; }
        }

6. Provide a way to terminate the thread, continue/single-thread terminate/all terminate


/// <summary>
        /// dowork Results the enumeration 
        /// </summary>
        public enum DoWorkResult
        {
            /// <summary>
            ///  Continue running, default 
            /// </summary>
            ContinueThread = 0,
            /// <summary>
            ///  Terminate the current thread 
            /// </summary>
            AbortCurrentThread = 1,
            /// <summary>
            ///  Terminate all threads 
            /// </summary>
            AbortAllThread = 2
        }

Do you ask? How do you use it? Don't worry... Please have a look at


/// <summary>
    ///  Download thread right .
    /// </summary>
    public class DownLoadQueueThread:QueueThreadBase<int>
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="list"> List of downloads ID</param>
        public DownLoadQueueThread(IEnumerable<int> list):base(list)
        {
        }
        /// <summary>
        ///  Every time multiple threads come here , Processing multithreading 
        /// </summary>
        /// <param name="pendingValue" The list of ID></param>
        /// <returns></returns>
        protected override DoWorkResult DoWork(int pendingID)
        {
            try
            {
                //.......... multithreading ....
                return DoWorkResult.ContinueThread;// There are no exceptions to keep the thread running ..
            }
            catch (Exception)
            {
                return DoWorkResult.AbortCurrentThread;// There are abnormal , You can terminate the current thread . Of course, . You can go on ,
                //return  DoWorkResult.AbortAllThread; // Under special circumstances  , There is an exception to terminate all threads ...
            }
            //return base.DoWork(pendingValue);
        }
    }
 usage 

Conclusion:

When multithreaded. Need not to is you don't use. Multithreaded programming base, 1 shall be, if you feel a little difficult, then you can learn and draw lessons from somebody else already. Little detours, is our programmers after runs. Based on the communication attitude and gratitude mentality, contributing to people in need.


Related articles: