Tool.Net 开源-ManagedThreadPool类

移除Tool.Utils.ManagedThreadPool类

移除原因:因为.net5中已经将Thread类中很多线程操作函数,声明为已过时,导致用户无法正常使用该类,现将该类公开。

源码公开如下:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace Tool.Utils
{
    /// <summary>
    ///用C#托管代码实现的线程池
    /// 它在管理线程的时候,有一个缓存线程的池,即一个ArrayList对象
    /// 它一开始就初始化了一定数量的线程,并通过ProcessQueuedItems方法保证异步执行进入池中的队列任务(那个死循环有时可能导致CPU过分忙碌),
    /// 这样在分配异步任务的时候,就省去了频繁去创建(new)一个线程
    /// </summary>
    public class ManagedThreadPool
    {
        #region Constants
        /// <summary>Maximum number of threads the thread pool has at its disposal.</summary>
        private const int _maxWorkerThreads = 10;
        #endregion

        #region Member Variables
        /// <summary>Queue of all the callbacks waiting to be executed.</summary>
        private static Queue _waitingCallbacks;
        /// <summary>
        /// Used to signal that a worker thread is needed for processing.  Note that multiple
        /// threads may be needed simultaneously and as such we use a semaphore instead of
        /// an auto reset event.
        /// </summary>
        private static Semaphore _workerThreadNeeded;
        /// <summary>List of all worker threads at the disposal of the thread pool.</summary>
        private static ArrayList _workerThreads;
        /// <summary>Number of threads currently active.</summary>
        private static int _inUseThreads;
        /// <summary>Lockable object for the pool.</summary>
        private static object _poolLock = new object();
        #endregion

        #region Construction and Finalization
        /// <summary>Initialize the thread pool.</summary>
        static ManagedThreadPool() { Initialize(); }

        /// <summary>Initializes the thread pool.</summary>
        private static void Initialize()
        {
            // Create our thread stores; we handle synchronization ourself
            // as we may run into situtations where multiple operations need to be atomic.
            // We keep track of the threads we've created just for good measure; not actually
            // needed for any core functionality.
            _waitingCallbacks = new Queue();
            _workerThreads = new ArrayList();
            _inUseThreads = 0;

            // Create our "thread needed" event
            _workerThreadNeeded = new Semaphore(0);

            // Create all of the worker threads
            for (int i = 0; i < _maxWorkerThreads; i++)
            {
                // Create a new thread and add it to the list of threads.
                Thread newThread = new Thread(new ThreadStart(ProcessQueuedItems));
                _workerThreads.Add(newThread);

                // Configure the new thread and start it
                newThread.Name = "ManagedPoolThread #" + i.ToString();
                newThread.IsBackground = true;
                newThread.Start();
            }
        }
        #endregion

        #region Public Methods
        /// <summary>Queues a user work item to the thread pool.</summary>
        /// <param name="callback">
        /// A WaitCallback representing the delegate to invoke when the thread in the 
        /// thread pool picks up the work item.
        /// </param>
        public static void QueueUserWorkItem(WaitCallback callback)
        {
            // Queue the delegate with no state
            //Logger.Debug(string.Format("添加线程操作方法:{0},Target:{1}", callback.Method.Name, callback.Target.ToString()));
            QueueUserWorkItem(callback, null);
        }

        /// <summary>Queues a user work item to the thread pool.</summary>
        /// <param name="callback">
        /// A WaitCallback representing the delegate to invoke when the thread in the 
        /// thread pool picks up the work item.
        /// </param>
        /// <param name="state">
        /// The object that is passed to the delegate when serviced from the thread pool.
        /// </param>
        public static void QueueUserWorkItem(WaitCallback callback, object state)
        {
            // Create a waiting callback that contains the delegate and its state.
            // At it to the processing queue, and signal that data is waiting.
            WaitingCallback waiting = new WaitingCallback(callback, state);
            lock (_poolLock) { _waitingCallbacks.Enqueue(waiting); }
            _workerThreadNeeded.AddOne();
        }

        /// <summary>Empties the work queue of any queued work items.  Resets all threads in the pool.</summary>
        public static void Reset()
        {
            lock (_poolLock)
            {
                // Cleanup any waiting callbacks
                try
                {
                    // Try to dispose of all remaining state
                    foreach (object obj in _waitingCallbacks)
                    {
                        WaitingCallback callback = (WaitingCallback)obj;
                        if (callback.State is IDisposable) ((IDisposable)callback.State).Dispose();
                    }
                }
                catch { }

                // Shutdown all existing threads
                try
                {
                    foreach (Thread thread in _workerThreads)
                    {
                        if (thread != null) thread.Abort("reset");
                    }
                }
                catch { }

                // Reinitialize the pool (create new threads, etc.)
                Initialize();
            }
        }
        #endregion

        #region Properties
        /// <summary>Gets the number of threads at the disposal of the thread pool.</summary>
        public static int MaxThreads { get { return _maxWorkerThreads; } }
        /// <summary>Gets the number of currently active threads in the thread pool.</summary>
        public static int ActiveThreads { get { return _inUseThreads; } }
        /// <summary>Gets the number of callback delegates currently waiting in the thread pool.</summary>
        public static int WaitingCallbacks { get { lock (_poolLock) { return _waitingCallbacks.Count; } } }
        #endregion

        #region Thread Processing


#if NET1
        /// <summary>Event raised when there is an exception on a threadpool thread.</summary>
        public static event UnhandledExceptionEventHandler UnhandledException;
#endif

        /// <summary>A thread worker function that processes items from the work queue.</summary>
        private static void ProcessQueuedItems()
        {
            // Process indefinitely
            while (true)
            {
                _workerThreadNeeded.WaitOne();

                // Get the next item in the queue.  If there is nothing there, go to sleep
                // for a while until we're woken up when a callback is waiting.
                WaitingCallback callback = null;

                // Try to get the next callback available.  We need to lock on the 
                // queue in order to make our count check and retrieval atomic.
                lock (_poolLock)
                {
                    if (_waitingCallbacks.Count > 0)
                    {
                        try { callback = (WaitingCallback)_waitingCallbacks.Dequeue(); }
                        catch { } // make sure not to fail here
                    }
                }

                if (callback != null)
                {
                    // We now have a callback.  Execute it.  Make sure to accurately
                    // record how many callbacks are currently executing.
                    try
                    {
                        Interlocked.Increment(ref _inUseThreads);
                        callback.Callback(callback.State);
                    }

                    catch (Exception)
                    {

                    }

                    finally
                    {
                        Interlocked.Decrement(ref _inUseThreads);
                    }
                }
            }
        }
        #endregion

        /// <summary>Used to hold a callback delegate and the state for that delegate.</summary>
        private class WaitingCallback
        {
            #region Member Variables
            /// <summary>Callback delegate for the callback.</summary>
            private WaitCallback _callback;
            /// <summary>State with which to call the callback delegate.</summary>
            private object _state;
            #endregion

            #region Construction
            /// <summary>Initialize the callback holding object.</summary>
            /// <param name="callback">Callback delegate for the callback.</param>
            /// <param name="state">State with which to call the callback delegate.</param>
            public WaitingCallback(WaitCallback callback, object state)
            {
                _callback = callback;
                _state = state;
            }
            #endregion

            #region Properties
            /// <summary>Gets the callback delegate for the callback.</summary>
            public WaitCallback Callback { get { return _callback; } }
            /// <summary>Gets the state with which to call the callback delegate.</summary>
            public object State { get { return _state; } }
            #endregion
        }
    }

    /// <summary>
    /// Implementation of Dijkstra's PV Semaphore based on the Monitor class.
    /// </summary>
    public class Semaphore
    {
        #region Member Variables
        /// <summary>The number of units alloted by this semaphore.</summary>
        private int _count;
        /// <summary>Lock for the semaphore.</summary>
        private object _semLock = new object();
        #endregion

        #region Construction
        /// <summary> Initialize the semaphore as a binary semaphore.</summary>
        public Semaphore()
            : this(1)
        {
        }

        /// <summary> Initialize the semaphore as a counting semaphore.</summary>
        /// <param name="count">Initial number of threads that can take out units from this semaphore.</param>
        /// <exception cref="ArgumentException">Throws if the count argument is less than 0.</exception>
        public Semaphore(int count)
        {
            if (count < 0) throw new ArgumentException("Semaphore must have a count of at least 0.", "count");
            _count = count;
        }
        #endregion

        #region Synchronization Operations
        /// <summary>V the semaphore (add 1 unit to it).</summary>
        public void AddOne() { V(); }

        /// <summary>P the semaphore (take out 1 unit from it).</summary>
        public void WaitOne() { P(); }

        /// <summary>P the semaphore (take out 1 unit from it).</summary>
        public void P()
        {
            // Lock so we can work in peace.  This works because lock is actually
            // built around Monitor.
            lock (_semLock)
            {
                // Wait until a unit becomes available.  We need to wait
                // in a loop in case someone else wakes up before us.  This could
                // happen if the Monitor.Pulse statements were changed to Monitor.PulseAll
                // statements in order to introduce some randomness into the order
                // in which threads are woken.
                while (_count <= 0) Monitor.Wait(_semLock, Timeout.Infinite);
                _count--;
            }
        }

        /// <summary>V the semaphore (add 1 unit to it).</summary>
        public void V()
        {
            // Lock so we can work in peace.  This works because lock is actually
            // built around Monitor.
            lock (_semLock)
            {
                // Release our hold on the unit of control.  Then tell everyone
                // waiting on this object that there is a unit available.
                _count++;
                Monitor.Pulse(_semLock);
            }
        }

        /// <summary>Resets the semaphore to the specified count.  Should be used cautiously.</summary>
        public void Reset(int count)
        {
            lock (_semLock) { _count = count; }
        }
        #endregion
    }
}

SmartThreadPool是大名鼎鼎的.Net线程池项目,基于.Net开发,比.Net内置的线程池更胜一筹。1、为什么需要使用线程池(Thread Pool)减少线程间上下文切换。线程执行一定的时间片后,系统会自动把cpu切换给另一个线程使用,这时还需要保存当 前的线程上下文状态,并加载新线程的上下文状态。当程序中有大量的线程时,每个线程分得的时间片会越来越少,可能会出现线程未处理多少操作,就需要切换到 另一线程,这样频繁的线程间上下文切换会花费大量的cpu时间。减少内存占用。系统每创建一条物理线程,需要大概花费1MB的内存空间,许多程序喜欢先创建多条物理线程,并 周期轮询来处理各自的任务,这样既消耗了线程上下文切换的时间,还浪费了内存。这些任务可能只需要一条线程就能满足要求。假如某一任务需要执行较长的周 期,线程池还可以自动增加线程,并在空闲时,销毁线程,释放占用的内存。2、为什么不使用.Net默认的线程池.Net默认的线程池(ThreadPool)是一个静态,所以是没办法自己创建一个新的程序池的。默认的线程池与应用程序域 (AppDomain)挂钩,一个AppDomain只有一个线程池。假如在线程池中执行了一个周期较长的任务,一直占用着其中一个线程,可能就会影响到 应用程序域中的其他程序的性能。例如,假如在Asp.Net的线程池中执行一个周期较长的任务,就会影响请求的并发处理能力(线程池默认有个最大线程 数)。 3、SmartThreadPool特性和优点    SmartThreadPool特性如下:可创建线程池实例。可动态调整线程池工作线程数量。WorkItem 可以返回信息。未执行 WorkItem 可被取消。WorkItem 执行时可使用调用者上下文。调用者可等待多个或全部 WorkItem 执行结束。WorkItem 允许拥有一个执行结束时被执行的 PostExecute 回调委托。可以向 WorkItem 传递一个状态对象,并且会在执行结束时自动调用 IDisposable.Dispose()。WorkItem 异常会传递给调用者。支持 WorkItem 分组。可挂起线程池或分组。可以设置 WorkItem 优先级。可以设置线程优先级。4、使用示例 最简单的使用方法:// 创建一个线程池 SmartThreadPool smartThreadPool = new SmartThreadPool();    // 执行任务 smartThreadPool.QueueWorkItem(() => {      Console.WriteLine("Hello World!"); });带返回值的任务:// 创建一个线程池 SmartThreadPool smartThreadPool = new SmartThreadPool();   // 执行任务 var result = smartThreadPool.QueueWorkItem(() => {     var sum = 0;     for (var i = 0; i  {     //模拟计算较长时间     Thread.Sleep(5000);       return 3; });   var result2 = smartThreadPool.QueueWorkItem(() => {     //模拟计算较长时间     Thread.Sleep(3000);       return 5; });   bool success = SmartThreadPool.WaitAll(     new IWorkItemResult[] { result1, result2 });   if (success) {     // 输出结果     Console.WriteLine(result1.Result);     Console.WriteLine(result2.Result); }5、结论 使用SmartThreadPool可以简单就实现支持多线程的程序,由线程池来管理线程,可以减少死锁的出现。SmartThreadPool还支持简单的生产者-消费者模式,当不需要对任务进行持久化时,还是很好用的。 6、扩展阅读 http://www.codeproject.com/KB/threads/smartthreadpool.aspx http://smartthreadpool.codeplex.com/http://www.albahari.com/threading/ 标签:线程池
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值