上一篇(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即可。