并发任务管理器AsyncTaskManager

//-------------------------------------------------------------------------- 
//  
//  Copyright (c) BUSHUOSX.  All rights reserved.  
//  
//  File: AsyncTaskManager.cs 
//
//  Version:1.1.0.6
//
//  Datetime:20170813
// 
//-------------------------------------------------------------------------- 


using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;

namespace BUSHUOSX
{
    class AsyncTaskManager
    {
        /// <summary>
        /// 缓存的任务队列
        /// </summary>
        readonly Queue<Task> _taskQueue = new Queue<Task>();

        /// <summary>
        /// 工作锁,保护_taskQueue
        /// </summary>
        SpinLock _workLock;

        /// <summary>
        /// 工作信号,与MaxConcurrencyLevel控制并行量
        /// </summary>
        SemaphoreSlim _workSemaphore;

        /// <summary>
        /// 工作线程取消标志
        /// </summary>
        CancellationTokenSource _ctsCancel;
        /// <summary>
        /// 工作器每次启动的工作时限
        /// </summary>
        int _timeoutMillisecond;
        /// <summary>
        /// 工作线程
        /// </summary>
        Task _worker;

        /// <summary>
        /// 工作器状态
        /// </summary>
        private bool IsWorking { get; set; }

        /// <summary>
        /// 任务最大并发量
        /// </summary>
        public int MaxConcurrencyLevel { get; }

        /// <summary>
        /// 内部工作器将在队列中有任务时自动启动。否则由Start方法启动。
        /// </summary>
        public bool AutoRunWorker { get; }

        /// <summary>
        /// 队列中的任一任务完成时,都将调用
        /// </summary>
        private Action<Task> _callbackOnAnyTaskComplited;

        /// <summary>
        /// 控制异步任务的并发量。
        /// 注意:只能严格控制stauts为Created的任务
        /// </summary>
        /// <param name="maxConcurrencyLevel">最大并发数。小于等于0时设置为int.MaxValue</param>
        /// <param name="callbackOnAnyTaskComplited">不为null时,队列中的任一任务完成后都将传递给此回调方法</param>
        /// <param name="autoRunWorker">指示内部工作器是在内部队列排入任务时自动启动,还是由Start方法启动。</param>
        /// <param name="timeout">调度完所有任务的时限。小于等于0时不设置超时</param>
        public AsyncTaskManager(int maxConcurrencyLevel, Action<Task> callbackOnAnyTaskComplited = null, bool autoRunWorker = true, int timeoutMillisecond = 0)
        {
            _callbackOnAnyTaskComplited = callbackOnAnyTaskComplited;
            AutoRunWorker = autoRunWorker;
            MaxConcurrencyLevel = maxConcurrencyLevel <= 0 ? int.MaxValue : maxConcurrencyLevel;
            _timeoutMillisecond = timeoutMillisecond <= 0 ? 0 : timeoutMillisecond;
        }

        /// <summary>
        /// 排入一个任务到内部队列,该队列中的任务将被依次调用。
        /// </summary>
        /// <param name="task">要排队的任务。注意:只能严格控制stauts为Created的任务</param>
        /// <param name="callbackOnTaskComplited">task任务完成时回调。如果所有任务使用同样的回调方法,建议使用构造函数中的callbackOnAnyTaskComplited</param>
        public void QueueTask(Task task, Action<Task> callbackOnTaskComplited = null)
        {
            if (task == null) return;
            if (null == callbackOnTaskComplited)
            {
                EnqueueTask(task);
            }
            else
            {
                EnqueueTask(task.ContinueWith(callbackOnTaskComplited));
            }
            if (AutoRunWorker)
            {
                notifyStartWork();
            }
        }

        /// <summary>
        /// 枚举任务到内部队列,该队列中的任务将被依次调用。
        /// </summary>
        /// <param name="tasks">要排队的任务。注意:只能严格控制stauts为Created的任务</param>
        /// <param name="callbackOnTaskComplited">tasks中的每个任务完成时回调</param>
        public void QueueTask(IEnumerable<Task> tasks, Action<Task> callbackOnTaskComplited = null)
        {
            foreach (var item in tasks)
            {
                if (item == null) break;
                if (null == callbackOnTaskComplited)
                {
                    EnqueueTask(item);
                }
                else
                {
                    EnqueueTask(item.ContinueWith(callbackOnTaskComplited));
                }
            }
            if (AutoRunWorker)
            {
                notifyStartWork();
            }
        }

        /// <summary>
        /// 返回此刻队列中的任务。
        /// </summary>
        /// <returns></returns>
        public Task[] GetQueueTask()
        {
            bool gotlock = false;
            try
            {
                _workLock.Enter(ref gotlock);
                if (_taskQueue.Count > 0)
                {
                    return _taskQueue.ToArray();
                }
                else
                {
                    return null;
                }
            }
            finally
            {
                if (gotlock) _workLock.Exit();
            }
        }

        /// <summary>
        /// 启动内部工作器。
        /// 注意:为降低资源占用,该工作器在内部队列为空时会自动退出。
        /// </summary>
        public void Start()
        {
            notifyStartWork();
        }

        /// <summary>
        /// 阻塞线程,等待内部工作器运行结束
        /// </summary>
        /// <returns>RanToCompletion:所有队列任务已被调度。Canceled:手动取消或挂起了任务,或任务超时。Faulted:未知错误。</returns>
        public TaskStatus WaitTaskSchdulerComplited()
        {
            if (_worker == null) throw new NotSupportedException("_worker is null");
            try
            {
                _worker.Wait();
            }
            catch (Exception)
            {
            }
            return _worker.Status;
        }

        /// <summary>
        /// 挂起队列中剩余的任务。稍后可以使用Continue方法继续。
        /// </summary>
        public void Suspend()
        {
            stopWorkThread(false);
        }

        /// <summary>
        /// 停止工作器,并清空内部任务队列还未调用的任务。
        /// 已调用的任务还将继续运行。
        /// </summary>
        public void Cancel()
        {
            stopWorkThread(true);
        }

        /// <summary>
        /// 停止工作器
        /// </summary>
        /// <param name="clearTasks">true时清空内部任务队列</param>
        private void stopWorkThread(bool clearTasks)
        {
            if (IsWorking)
            {
                _ctsCancel.Cancel();
                if (clearTasks)
                {
                    bool gotlock = false;
                    try
                    {
                        _workLock.Enter(ref gotlock);
                        _taskQueue.Clear();
                    }
                    finally
                    {
                        if (gotlock) _workLock.Exit();
                    }
                }
            }
        }

        /// <summary>
        /// 继续之前挂起的任务。
        /// </summary>
        public void Continue()
        {
            notifyStartWork();
        }


        /// <summary>
        /// 内部启动工作器
        /// </summary>
        private void notifyStartWork()
        {
            if (IsWorking) return;

            //初始化
            _ctsCancel = new CancellationTokenSource();
            if (_timeoutMillisecond > 0)
            {
                _ctsCancel.CancelAfter(_timeoutMillisecond);
            }
            _workLock = new SpinLock();
            _workSemaphore = new SemaphoreSlim(MaxConcurrencyLevel, MaxConcurrencyLevel);

            _worker = Task.Run(new Action(workerThread), _ctsCancel.Token);
        }

        /// <summary>
        /// 任一任务完成时调用
        /// </summary>
        /// <param name="task"></param>
        private void anyTaskComplited(Task task)
        {
            _workSemaphore.Release();
            //todo task
            _callbackOnAnyTaskComplited?.Invoke(task);
            //Debug.WriteLine("完成任务{0}:{1}", task.Id, task.Status.ToString());
        }

        /// <summary>
        /// 工作器线程执行方法。只应存在一个。
        /// </summary>
        private void workerThread()
        {
            IsWorking = true;
            Debug.WriteLine("工作线程启动……");
            try
            {
                Task tmp = null;
                while (true)
                {
#if DEBUG
                    //不恰当的操作,只为屏蔽调试时错误
                    //会导致_worker状态为RanToCompletion
                    try
                    {
                        _workSemaphore.Wait(_ctsCancel.Token);
                    }
                    catch (OperationCanceledException)
                    {
                        //_ctsCancel.Token.ThrowIfCancellationRequested();
                        return;
                    }
#else
                    _workSemaphore.Wait(_ctsCancel.Token);

                    //传递取消状态
                    _ctsCancel.Token.ThrowIfCancellationRequested();
#endif


                    tmp = DequeueTask();
                    if (tmp != null)
                    {
                        if (tmp.Status == TaskStatus.Created)
                        {
                            tmp.Start();
                        }
                        tmp.ContinueWith(anyTaskComplited);
                    }
                    else
                    {
                        if (_taskQueue.Count == 0)
                        {
                            Debug.WriteLine("workerAsync:taskQueue is empty");
                            break;
                        }
                    }
                }
            }
            finally
            {
                //notifyEndWork();
                IsWorking = false;
                Debug.WriteLine("工作线程结束……");
            }
        }

        /// <summary>
        /// 排入任务,期望线程安全
        /// </summary>
        /// <param name="task"></param>
        private void EnqueueTask(Task task)
        {
            bool gotlock = false;
            try
            {
                _workLock.Enter(ref gotlock);
                _taskQueue.Enqueue(task);
            }
            finally
            {
                if (gotlock) _workLock.Exit();
            }

        }

        /// <summary>
        /// 弹出任务,期望线程安全
        /// </summary>
        /// <returns></returns>
        private Task DequeueTask()
        {
            bool gotlock = false;
            try
            {
                _workLock.Enter(ref gotlock);
                if (_taskQueue.Count > 0)
                {
                    return _taskQueue.Dequeue();
                }
                else
                {
                    return null;
                }
            }
            finally
            {
                if (gotlock) _workLock.Exit();
            }
        }
    }
}

 

posted @ 2017-08-13 00:07  倚舟笑沧海  阅读(1471)  评论(0编辑  收藏  举报