实现一个双缓冲队列(二)

上一篇(http://www.cnblogs.com/cqgis/p/6403262.html)实现了一个双缓冲队列的例子,我们把消费者的方法直接写到了队例里,为了达到更好的复用,这一篇分享一个封装的泛型类

     /// <summary>
    /// 双缓冲队列
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class DoubleBufferedQueue<T> : IDisposable
    {
        private readonly int _millisecond;

        /// <summary>
        /// 
        /// </summary>
        private readonly Queue<T> _queue1 = new Queue<T>();
        private readonly Queue<T> _queue2 = new Queue<T>();

        private readonly ManualResetEvent _equeueLock = new ManualResetEvent(true);
        private readonly ManualResetEvent _dequeuelock = new ManualResetEvent(false);

        private readonly AutoResetEvent _autoReset = new AutoResetEvent(true);


        private volatile Queue<T> _currentQueue;
        private readonly BackgroundWorker _backgroundWorker;

        /// <summary>
        /// 双缓冲队列
        /// </summary>
        /// <param name="millisecond">消费者线程处理一批后,需要延时的时间,实现定时间隔操作</param>
        public DoubleBufferedQueue(int millisecond = 0)
        {
            _millisecond = millisecond;
            _currentQueue = _queue1;

            _backgroundWorker = new BackgroundWorker();
            _backgroundWorker.DoWork += BackgroundWorker_DoWork;
            _backgroundWorker.RunWorkerAsync();
        }

        /// <summary>
        /// 消息者处理方法
        /// </summary>
        public Action<Queue<T>> ConsumerAction { get; set; }


        private void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            while (true)
            {
                var readQueue = this.GetDequeue();
                ConsumerAction?.Invoke(readQueue);

                if (_millisecond > 0)
                    Thread.Sleep(TimeSpan.FromMilliseconds(_millisecond));
            }
            // ReSharper disable once FunctionNeverReturns
        }

        public void Equeue(T item, Action<T> action = null)
        {
            this._dequeuelock.WaitOne();
            this._equeueLock.Reset();

            _currentQueue.Enqueue(item);
            action?.Invoke(item);
            _equeueLock.Set();
            _autoReset.Set();
        }

        private Queue<T> GetDequeue()
        {
            this._autoReset.WaitOne();  //这个信号量是保证在没有成员入队列的时间,不进行其它操作

            this._dequeuelock.Reset();  //注意两把锁的顺序,不然会造成死锁的问题
            this._equeueLock.WaitOne();

            var readQueue = _currentQueue;
            _currentQueue = (_currentQueue == _queue1) ? _queue2 : _queue1;

            this._dequeuelock.Set();
            return readQueue;
        }

        public void Dispose()
        {
            _dequeuelock.Reset();

            ConsumerAction?.Invoke(_queue1);
            ConsumerAction?.Invoke(_queue2);
             
            _backgroundWorker?.Dispose();
        }
    }

  在调用的时候,指定ConsumerAction即可。

原文地址:https://www.cnblogs.com/cqgis/p/6439027.html