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