VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > Python基础教程 >
  • C#教程之实现一个双缓冲队列(二)

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

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
/// <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 { getset; }
 
 
    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();
    }
}