本篇体验使用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. ajax与302响应

    在ajax请求中,如果服务器端的响应是302 Found,在ajax的回调函数中能够获取这个状态码吗?能够从Response Headers中得到Location的值进行重定向吗?让我们来一起看看实际 ...

  2. UFLDL 教程学习笔记(一)

    ufdl的新教程,从基础学起.第一节讲的是线性回归.主要目的是熟悉目标函数,计算梯度和优化. 按着教程写完代码后,总是编译出错,一查是mex的原因,实在不想整了. 这位博主用的是向量,比较简洁:htt ...

  3. windows 2008 启用.NET Framework 3.5

    Win2008下已经集成了.NET 3.5.1 framework,需要在管理界面打开! 方法和步骤是: 服务器管理器 -> 功能 -> 添加功能 然后在“选择功能”界面勾选“.NET F ...

  4. 1 、在Linux(centos6.8)系统下的JDK安装与配置

    一.解压jdk安装包: 附上jdk1.8的下载地址: http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-21 ...

  5. **linux实用命令之如何移动文件夹及文件下所有文件

    http://www.linuxde.net/2013/02/12448.html 格式: mv [选项(option)] 源文件或目录 目标文件或目录 使用命令: mv webdata /bin/u ...

  6. 【LOJ】#2109. 「JLOI2015」骗我呢

    题解 我深思熟虑许久才算是明白个大概的计数问题吧 先是转化成一个矩形,列一条直线y = x,y = x - (m + 1)我们从(0,0)走到(n + m + 1,m + 1)就是答案 因为我们起始相 ...

  7. 008 jquery过滤选择器-----------(子元素过滤选择器)

    1.介紹 2.程序 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> < ...

  8. Java动态性之反射机制(reflection)

    说到反射机制,第一次接触的人可能会比较懵,反射?什么反射?怎么反射?反射是干嘛的?下面我将在这篇文章中讲讲Java的反射机制 不过在这之前,还有一个问题需要解决,标题名中的动态性,说起动态性,我先介绍 ...

  9. Bootstrap css-表格

    前言:整理的东西比较基础,有不足的地方欢迎大家批评指正! 1,Bootstrap基本的表格结构 源代码: <table class="table">   <cap ...

  10. HTTP错误405

    405 - 用来访问本页面的(方法不被允许) HTTP 错误 405 -禁止访问资源 HTTP 错误 405 405 不允许此方法 对于请求所标识的资源,不允许使用请求行中所指定的方法.请确保为所请求 ...