更新时间:2017-12-03 11:58:29浏览次数:1+次
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace SuiBao.Utility
{
///阻塞队列(BlockingQueue)是一个支持两个附加操作的队列。这两个附加的操作是:在队列为空时,获取元素的线程会等待队列变为非空。当队列满时,存储元素的线程会等待队列可用。阻塞队列常用于生产者和消费者的场景,生产者是往队列里添加元素的线程,消费者是从队列里拿元素的线程。阻塞队列就是生产者存放元素的容器,而消费者也只从容器里拿元素。
//阻塞队列 需要实现两个功能: 使线程等待与唤醒线程. 具体介绍如下:
// 在极端条件下, 需要挂起线程, 等待队列满足条件后,再去执行添加或提取 操作
// 待队列满足了条件之后, 通知线程去继续其挂起之前的操作....
//涉及到的技术:
//线程同步(此实例用到了lock) 与 线程间通信(此示例用到了event)
//
// 可能产生死锁的分析:
// 在某个时刻,队列为空或者是已满, 此时生产者未能存入数据或者还在存入数据到队列中, 这就会产生使得队列出错
// 如果此时, 消费者对队列在进行操作就会产生死锁...由于之前的生产者的操作使得队列出了问题并没有释放锁, 此时就会造成死锁
// 这是从预防死锁的角度来解决死锁问题
public class BlockQueue<T>
{
private Queue<T> _inner_queue = null;
private ManualResetEvent _dequeue_wait = null;
public int Count
{
get { return _inner_queue.Count; }
}
public BlockQueue(int capacity = -1)
{
this._inner_queue = capacity == -1 ? new Queue<T>() : new Queue<T>(capacity);
this._dequeue_wait = new ManualResetEvent(false);
}
// 入队加锁
public void EnQueue(T item)
{
if (this._IsShutdown == true) throw new InvalidOperationException("服务未开启.[EnQueue]");
lock (this._inner_queue)
{
this._inner_queue.Enqueue(item);
this._dequeue_wait.Set();
}
}
// 出队加锁
public T DeQueue(int waitTime)
{
bool _queueEmpty = false;
T item = default(T);
while (true)
{
lock (this._inner_queue)
{
// 判断队列中是否有元素....
if (this._inner_queue.Count > 0)
{
item = this._inner_queue.Dequeue();
this._dequeue_wait.Reset();
//break;
}
else
{
if (this._IsShutdown == true)
{
throw new InvalidOperationException("服务未开启[DeQueue].");
}
else
{
_queueEmpty = true;
}
}
}
if (item != null)
{
return item;
}
if (_queueEmpty)
{
this._dequeue_wait.WaitOne(waitTime);
}
}
}
private bool _IsShutdown = false;
public void Shutdown()
{
this._IsShutdown = true;
this._dequeue_wait.Set();
}
public void Clear()
{
this._inner_queue.Clear();
}
}
}
那么.net中有没有封装好的阻塞队列?有啊!BlockingCollection<>类,其实我之前写的好些关于线程的文章都说到了这个类库,用到的地方也多。该类默认的容器是ConcurrentQueue,因此,同步就做好了,而且该类还实现了阻塞的功能:相关资讯