博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
使用C#的泛型队列Queue实现生产消费模式
阅读量:7013 次
发布时间:2019-06-28

本文共 2302 字,大约阅读时间需要 7 分钟。

 

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

 

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

 

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

 

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

 

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

 

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

 

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

 

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

 

 
//有关生产消费的泛型类
public class ProducerConsumer
{
//用来存储生产者的队列
private readonly Queue
queue = new Queue
();
 
//锁
private readonly object queueLocker = new object();
 
//消费行为
private readonly Action
consumerAction;
 
//出列的时候需要检查队列中是否有元素,如果没有,需要阻塞
private readonly AutoResetEvent queueWaitHandle = new AutoResetEvent(false);
 
public ProducerConsumer(Action
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
(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();
 
}
}
 
 

转载地址:http://gdqtl.baihongyu.com/

你可能感兴趣的文章
Android 虚拟机 程序安装目录
查看>>
深入学习Hive应用场景及架构原理
查看>>
07-01 Java 封装
查看>>
HDU_1143_tri tiling
查看>>
codeforces_1075_C. The Tower is Going Home
查看>>
使用BBED模拟Oracle数据库坏块
查看>>
C# 关于XML的简单操作实例
查看>>
ggplot2:画世界地图和中国地图 合并数据 增添信息 标记
查看>>
VertexBuffer渲染次序
查看>>
div高度自适应
查看>>
python中使用 xpath
查看>>
集中管理:领导者,不能不考虑的几件事之—— 拿什么辅助你,我的决策?(一)...
查看>>
四、物理优化(6)数据库引擎优化顾问
查看>>
我的友情链接
查看>>
关于VirtualBox虚拟机安装GhostXP出现蓝屏proce***.sys 的解决办法
查看>>
浅谈 C#委托
查看>>
Atitit.跨语言反射api 兼容性提升与增强 java c#。Net php js
查看>>
【Thread】多线程的异常处理?
查看>>
H.264 CODEC
查看>>
计算机图形学中的经常使用模型
查看>>