本篇体验使用C#的泛型队列Queue<T>实现生产消费模式。

如果把生产消费想像成自动流水生产线的话,生产就是流水线的物料,消费就是某种设备对物料进行加工的行为,流水线就是队列。

现在,要写一个体现生产消费模式的泛型帮助类,比如叫ProducerConsumer<T>。

该类肯定会维护一个有关生产、物料的Queue<T>类型的字段,还存在一个有关消费、Action<T>类型的字段。

在ProducerConsumer类的构造函数中,为Action<T>类型的字段赋值,并开启后台有关消费的线程。

ProducerConsumer类肯定存在一个进队列的方法,并且要保证在多线程情况下,同一时间只有一个生产或物料进入队列。

ProducerConsumer类还存在一个有关消费的方法,并且保证在多线程情况下,同一时间只有一个生产或物料出列,并消费它。

另外,在生产或物料在出队列的时候,可能会出现队列中暂时没有生产或物料的情况,这时候我们希望线程阻塞一下,这需要通过AutoResetEvent实现。AutoResetEvent的大致原理是:当生产或物料进入队列的时候需要告诉AutoResetEvent一下,当队列中暂时没有生产或物料的时候,也需要告诉AutoResetEvent,让它来阻塞线程。

  //有关生产消费的泛型类
    public class ProducerConsumer<T>
    {
        //用来存储生产者的队列
        private readonly Queue<T>  queue = new Queue<T>();

        //锁
        private readonly object queueLocker = new object();

        //消费行为
        private readonly Action<T> consumerAction;

        //出列的时候需要检查队列中是否有元素,如果没有,需要阻塞
        private readonly AutoResetEvent queueWaitHandle = new AutoResetEvent(false);

        public ProducerConsumer(Action<T> consumerAction)
        {
            if (consumerAction == null)
            {
                throw new ArgumentNullException("consumerAction");
            }

            this.consumerAction = consumerAction;

            //后台开启一个线程开始消费生产者
            new Thread(this.ConsumeItems){IsBackground = true}.Start();
        }

        //进列
        public void Enqueue(T item)
        {
            //确保同一时间只有一个生产者进列
            lock (queueLocker)
            {
                queue.Enqueue(item);

                //每次进列都要设置AutoResetEvent事件
                this.queueWaitHandle.Set();
            }
        }

        //消费动作
        private void ConsumeItems()
        {
            while (true)
            {
                T nextItem = default(T);

                //标志,确认队列中的生产者是否存在
                bool doesItemExist;

                //确保同一时间只有一个生产者出列
                lock (this.queueLocker)
                {
                    //先确认队列中的生产者是否存在
                    doesItemExist = this.queue.Count > 0;
                    if (doesItemExist)
                    {
                        nextItem = this.queue.Dequeue();
                    }

                }

                //如果生产者存在,才消费生产者
                if (doesItemExist)
                {
                    this.consumerAction(nextItem);
                }
                else//否则的话,再等等下一个队列中的生产者
                {
                    this.queueWaitHandle.WaitOne();
                }

            }
        }
    }


客户端,针对多线程情形。

    class Program
    {
        static void Main(string[] args)
        {
            //实例化一个int类型的生产消费实例
            var producerConsumer = new ProducerConsumer<int>(i => Console.WriteLine("正在消费" + i));

            Random random = new Random();

            //开启进队列线程
            var t1 = new Thread(() =>
            {
                for (int i = 0; i < 100; i++)
                {
                    producerConsumer.Enqueue(i);
                    Thread.Sleep(random.Next(0,5));
                }
            });

            var t2 = new Thread(() =>
            {
                for (int i = 0; i > -100; i--)
                {
                    producerConsumer.Enqueue(i);
                    Thread.Sleep(random.Next(0, 5));
                }
            });

            t1.Start();
            t2.Start();

            t1.Join();
            t2.Join();

            Thread.Sleep(50);

            Console.ReadKey();

        }
    }


使用C#的泛型队列Queue实现生产消费模式的更多相关文章

  1. C# 队列Queue,ConcurrentQueue,BlockingCollection 并发控制lock,Monitor,信号量Semaphore

    什么是队列? 队列Queues,是一种遵循先进先出的原则的集合,在.netCore中微软给我们提供了很多个类,就目前本人所知的有三种,分别是标题提到的:Queue.ConcurrentQueue.Bl ...

  2. 消息队列Queue大全

    消息队列Queue大全 (http://queues.io/) 作业队列,消息队列和其他队列.几乎所有你能想到的都在这. 关于 那里有很多排队系统.他们每个人都不同,是为解决某些问题而创建的.这个页面 ...

  3. 使用队列queue实现一个简单的生产者消费者模型

    一.生产者消费者模型 我们去超市商店等地购买商品时,我们大部分人都会说自己是消费者,而超市的各大供货商.工厂等,自然而然地也就成了我们的生产者.如此一来,生产者有了,消费者也有了,那么将二者联系起来的 ...

  4. Python进阶(3)_进程与线程中的lock(线程中互斥锁、递归锁、信号量、Event对象、队列queue)

    1.同步锁 (Lock) 当全局资源(counter)被抢占的情况,问题产生的原因就是没有控制多个线程对同一资源的访问,对数据造成破坏,使得线程运行的结果不可预期.这种现象称为“线程不安全”.在开发过 ...

  5. 线程队列queue

    队列queue 队列用于线程之间安全的信息交换 队列和列表的区别:队列里的信息get()后就没了,而列表获取数据则是copy,原列表里的值还在 使用前先实例化队列 q = queue.Queue(ma ...

  6. 0032ActiveMQ之java编码实现生产者和消费者操作队列queue

    今天学习了入门级的用java编写生产者producer和消费者consumer操作activemq的queue队列,为了之后复习回顾,现做整理如下: maven工程的搭建此处不再讲解,在maven工程 ...

  7. python笔记9 线程进程 threading多线程模块 GIL锁 multiprocessing多进程模块 同步锁Lock 队列queue IO模型

    线程与进程 进程 进程就是一个程序在一个数据集上的一次动态执行过程.进程一般由程序.数据集.进程控制块三部分组成.我们编写的程序用来描述进程要完成哪些功能以及如何完成:数据集则是程序在执行过程中所需要 ...

  8. Python--线程队列(queue)、multiprocessing模块(进程对列Queue、管道(pipe)、进程池)、协程

    队列(queue) 队列只在多线程里有意义,是一种线程安全的数据结构. get与put方法 ''' 创建一个“队列”对象 import queue q = queue.Queue(maxsize = ...

  9. Python进阶【第二篇】多线程、消息队列queue

    1.Python多线程.多进程 目的提高并发 1.一个应用程序,可以有多进程和多线程 2.默认:单进程,单线程 3.单进程,多线程 IO操作,不占用CPU python的多线程:IO操作,多线程提供并 ...

随机推荐

  1. pymongo创建索引

    from database import db db_list = ["table1", "table2", "table3", " ...

  2. css1-puchong1

    HTML DOM (文档对象模型) 当网页被加载时,浏览器会创建页面的文档对象模型(Document Object Model). HTML DOM 模型被构造为对象的树. 一:HTML DOM 树 ...

  3. Android 7.0 行为变更

    Android 7.0 除了提供诸多新特性和功能外,还对系统和 API 行为做出了各种变更.本文重点介绍您应该了解并在开发应用时加以考虑的一些主要变更. 如果您之前发布过 Android 应用,请注意 ...

  4. VS2010上连接SQLite数据库

    VS2010连接SQLite数据库 Visual studio 2010及以上版本,连接SQLite数据库 1.在Sqlite开发站点下载SQLite的.exe安装包 Ctrl+F搜索这条语句:Thi ...

  5. fedroa20中将ssh,ssl升级到当前最新版本

    Fedroa20下手工安装openssh-server 本例以Fedroa20为例,需要下载:zlib-1.2.8.tar.openssl-1.0.2e.tar. openssh-7.1p1.tar. ...

  6. Eclipse代码注释模板-code template

    参考帖子blog.csdn.net/security08/article/details/5588013 操作步骤:打开Window->Preferences->Java->Code ...

  7. 前端架构之路:Windows下安装Nodejs步骤

      最近打算把我们的微信端用Vue.js重构,为什么选择Vue.js,一是之前使用的是传统的asp.net mvc,多页面应用用户体验比单页面要差.二是使用过Angular.js,感觉对开发人员要求较 ...

  8. 【LOJ】#2535. 「CQOI2018」九连环

    题解 简单分析一下,有\(k\)个环肯定是,我拆掉了\(k - 2\)个,留最左两个,1步拆掉最左的,这个时候我还要把这\(k - 2\)个环拼回去,拆一次\(k - 1\) 所以方案数就是\(f[k ...

  9. ubuntu14.0安装ITK的步骤

    (1) sudo apt-get install cmake (2) sudo apt-get install cmake-curses-gui (3)下载安装包InsightToolkit-4.11 ...

  10. 20172302『Java程序设计』课程 结对编程练习_四则运算第二周阶段总结

    一.结对对象 姓名:周亚杰 学号:20172302 担任角色:驾驶员(周亚杰) 伙伴第二周博客地址 二.本周内容 (一)继续编写上周未完成代码 1.本周继续编写代码,使代码支持分数类计算 2.相关过程 ...