• C# 阻塞队列 BlockingQueue<T>


    C#中的阻塞队列,在进行生产者、消费者消息通信时,可以大幅提升效率,队列无数据或满时进行阻塞。

        /// <summary>
        /// Description: 阻塞队列(泛型)
        ///              主要实现了队列为空时出队阻塞,队列已满时入队阻塞
        /// Author: BruceZhang
        /// Date:2017-4-18
        /// </summary>
        public class BlockingQueue<T>
        {
            #region Fields & Properties
            //队列名称
            private string m_name;
            //队列最大长度
            private readonly int m_maxSize;
            //FIFO队列
            private Queue<T> m_queue;
            //是否运行中
            private bool m_isRunning;
            //入队手动复位事件
            private ManualResetEvent m_enqueueWait;
            //出队手动复位事件
            private ManualResetEvent m_dequeueWait;
            //输出日志
            public Action<string> m_actionOutLog;
            /// <summary>
            /// 队列长度
            /// </summary>
            public int Count => m_queue.Count;
            #endregion
    
            #region Ctor
            public BlockingQueue(int maxSize, string name = "BlockingQueue", bool isRunning = false)
            {
                m_maxSize = maxSize;
                m_name = name;
                m_queue = new Queue<T>(m_maxSize);
                m_isRunning = isRunning;
                m_enqueueWait = new ManualResetEvent(false); // 无信号,入队waitOne阻塞
                m_dequeueWait = new ManualResetEvent(false); // 无信号, 出队waitOne阻塞
            }
            #endregion
    
            #region Private Method
    
            private void OutLog(string message)
            {
                m_actionOutLog?.Invoke(message);
            }
    
            #endregion
    
            #region Public Method
    
            /// <summary>
            /// 开启阻塞队列
            /// </summary>
            public void Open()
            {
                m_isRunning = true;
            }
    
            /// <summary>
            /// 关闭阻塞队列
            /// </summary>
            public void Close()
            {
                // 停止队列
                m_isRunning = false;
                // 发送信号,通知出队阻塞waitOne可继续执行,可进行出队操作
                m_dequeueWait.Set();
            }
    
            /// <summary>
            /// 入队
            /// </summary>
            /// <param name="item"></param>
            public void Enqueue(T item)
            {
                if (!m_isRunning)
                {
                    // 处理方式一 可直接抛出异常
                    //throw new InvalidCastException("队列终止,不允许入队");
                    // 处理方式二 可输出到日志,体验更好
                    OutLog($"{m_name} 队列终止,不允许入队");
                    return;
                }
    
                while (true)
                {
                    lock (m_queue)
                    {
                        // 如果队列未满,继续入队
                        if (m_queue.Count < m_maxSize)
                        {
                            m_queue.Enqueue(item);
                            // 置为无信号
                            m_enqueueWait.Reset();
                            // 发送信号,通知出队阻塞waitOne可继续执行,可进行出队操作
                            m_dequeueWait.Set();
                            // 输出日志
                            OutLog($"{m_name} 入队成功.");
                            break;
                        }
                    }
                    // 如果队列已满,则阻塞队列,停止入队,等待信号
                    m_enqueueWait.WaitOne();
                }
            }
    
            /// <summary>
            /// 出队
            /// </summary>
            /// <param name="item"></param>
            /// <returns></returns>
            public bool Dequeue(ref T item)
            {
                while (true)
                {
                    if (!m_isRunning)
                    {
                        lock (m_queue) return false;
                    }
                    lock (m_queue)
                    {
                        // 如果队列有数据,则执行出队
                        if (m_queue.Count > 0)
                        {
                            item = m_queue.Dequeue();
                            // 置为无信号
                            m_dequeueWait.Reset();
                            // 发送信号,通知入队阻塞waitOne可继续执行,可进行入队操作
                            m_enqueueWait.Set();
                            // 输出日志
                            OutLog($"{m_name} 出队成功.");
                            return true;
                        }
                    }
                    // 如果队列无数据,则阻塞队列,停止出队,等待信号
                    m_dequeueWait.WaitOne();
                }
            }
            #endregion
        }
    
  • 相关阅读:
    docker 会这些也够
    Linux 学会这些基本可以啦
    xxxxxxxxx
    Angular
    mongo
    node
    git clone 解决Permission Denied (publickey)问题
    vue项目如何刷新当前页面
    vue——动态路由以及地址传参
    vue 单页应用点击某个链接,跳转到新页面的方式
  • 原文地址:https://www.cnblogs.com/brucezhang80/p/BlockingQueue.html
Copyright © 2020-2023  润新知