using System;
using System.Threading;
using System.Collections.Generic;
class ProducerConsumerQueue : IDisposable
{
EventWaitHandle _wh = new AutoResetEvent (false);
Thread _worker;
readonly object _locker = new object();
Queue<string> _tasks = new Queue<string>();
public ProducerConsumerQueue()
{
_worker = new Thread (Work);
_worker.Start();
}
public void EnqueueTask (string task)
{
lock (_locker) _tasks.Enqueue (task);
_wh.Set();
}
public void Dispose()
{
EnqueueTask (null); // 通知消费者退出
_worker.Join(); // 等待消费者线程完成执行
_wh.Close(); // 释放所有系统资源
}
void Work()
{
while (true)
{
string task = null;
lock (_locker)
if (_tasks.Count > 0)
{
task = _tasks.Dequeue();
if (task == null) return;
}
if (task != null)
{
Console.WriteLine ("Performing task: " + task);
Thread.Sleep (1000); // 模拟执行工作...
}
else
_wh.WaitOne(); // 没有任务了,等待信号
}
}
}
//为保证线程安全,我们使用了一个锁来保护对Queue<string>的访问。在Dispose方法中,我们也显式关闭了等待句柄,因为在程序生命周期中,有可能会创建和销毁许多这个类的实例。
下边是测试这个队列的主方法:
static void Main()
{
using (ProducerConsumerQueue q = new ProducerConsumerQueue())
{
q.EnqueueTask ("Hello");
for (int i = 0; i < 10; i++) q.EnqueueTask ("Say " + i);
q.EnqueueTask ("Goodbye!");
}
// 使用 using 语句结束时会调用 q 的 Dispose 方法
// 该方法向队列中插入一个 null 的任务,并等待消费者完成退出。
}
输出结果:
Performing task: Hello
Performing task: Say 1
Performing task: Say 2
Performing task: Say 3
...
...
Performing task: Say 9
Goodbye!