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