C#中如何控制缓冲空间的上限

来源:互联网 发布:淘宝子账户认证二维码 编辑:程序博客网 时间:2024/04/25 14:18

       我们用C#基于“生产者/消费者”编程时,往往会用Queue、Hashtable或 Dictionary 泛型类型来作一个缓存,用于缓存“生产者”产生的数据,若“消费者”能及时处理这些数据,倒不成问题,但若某种原因,导致“消费者”没有及时处理,就可能导致内存被大量消耗,系统性能急剧下降,直到失去响应。如何有效地限制缓冲空间的上限?由于我们的“生产者”与“消费者”可能分别为多个线程,因此不能采用简单加锁的方式来解决,而是使用ManualResetEvent 或AutoResetEvent来实现线程间的消息传递。 解决方案如下代码所示:


    /// <summary>
    /// 这个例子用于演示如例控制一个缓冲的大小
    /// 此例中以一个队列为类,假定元素成员总数不得大于100个
    /// </summary>
    public class BufferManager
    {
        public Queue<int> buffer = new Queue<int>();
        private System.Threading.ManualResetEvent ev = new System.Threading.ManualResetEvent(false);

        /// <summary>
        /// 将对象添加到 Queue 的结尾处,模拟生产者。 Queue 的容量是指 Queue 可以保存的元素数。随着向 Queue 中添加元素,容量通过重新分配按需自动增加。
        /// 测试证明,如果不加限制地添加,可能会导致内存大量被占用,甚至系统停止响应
        /// </summary>
        /// <param name="item"></param>
        public void Enqueue(int item)
        {
            if (buffer.Count > 99)
            {
                //若缓冲大于99个成员,则阻塞线程
                ev.WaitOne();
            }
            lock (buffer)
            {
                buffer.Enqueue(item);
                //向队列(缓冲)添加一个元素后,判断一下元素个数是否已达上限,若已达上限,则发出阻塞通知
                if (buffer.Count > 99)
                {
                    ev.Reset();
                }
            }
        }

        /// <summary>
        /// 从 Queue 的开头移除的对象。模拟消费者。
        /// </summary>
        public void Dequeue()
        {
            if (buffer.Count > 0)
            {
                lock (buffer)
                {
                    buffer.Dequeue();
                    //从队列(缓冲取出一个元素后,通知被阻塞的线程继续)
                    ev.Set();
                }

            }

        }
    }

原创粉丝点击