我正在尝试
为类生产者/消费者编译大师'Joe Duffy'提出的代码(更多迭代器乐趣与生产者/消费者模式),但发生此错误:
(我使用的是visual studio 2010和net 4.0.3)
Program.cs(37,34):错误 CS0453:类型“T”必须是不可为空的值类型才能在泛型类型或方法“System.Nullable”中用作参数“T” Program.cs(11,40):(相关位置) Program.cs(37,61):错误 CS0453:类型“T”必须是不可为空的值类型才能在泛型类型或方法“System.Nullable”中用作参数“T” Program.cs(11,40):(相关位置) Program.cs(44,53):错误 CS0453:类型“T”必须是不可为空的值类型才能在泛型类型或方法“System.Nullable”中用作参数“T” Program.cs(11,40):(相关位置)
对我微薄的知识来说太多了!有人可以提出解决方案吗?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace ProducerConsumerClass
{
class Program
{
public abstract class Producer<T>
{
public Producer()
{
worker = new Thread(new ThreadStart(this.ProductionCycle));
}
private Queue<T> buffer = new Queue<T>();
public Thread worker;
private bool done;
public bool Done
{
get
{
return done;
}
}
public IEnumerable<T> ConsumerChannel
{
get
{
if (done)
throw new InvalidOperationException("Production is not currently active");
while (!done)
{
Nullable<T> consumed = new Nullable<T>();
//BUG: compiler crashes when using lock(...) construct within iterator
Monitor.Enter(buffer);
if (buffer.Count == 0)
Monitor.Wait(buffer);
if (buffer.Count > 0)
consumed = new Nullable<T>(buffer.Dequeue());
Monitor.Exit(buffer);
if (consumed.HasValue)
yield return consumed.Value;
}
yield break;
}
}
public void BeginProduction()
{
done = false;
worker.Start();
}
public void EndProduction()
{
done = true;
lock (buffer)
{
Monitor.PulseAll(buffer);
}
}
private void ProductionCycle()
{
while (!done)
{
T t = ProduceNext();
lock (buffer)
{
buffer.Enqueue(t);
Monitor.Pulse(buffer);
}
}
}
protected abstract T ProduceNext();
}
public abstract class Consumer<T>
{
public Consumer(Producer<T> producer)
{
this.producer = producer;
worker = new Thread(new ThreadStart(this.ConsumerCycle));
}
private Producer<T> producer;
public Thread worker;
private bool done = false;
public bool Done
{
get
{
return done;
}
}
public void BeginConsumption()
{
done = false;
worker.Start();
}
public void EndConsumption()
{
done = true;
}
private void ConsumerCycle()
{
foreach (T t in producer.ConsumerChannel)
{
Consume(t);
if (done)
break;
}
}
protected abstract void Consume(T t);
}
class RandomNumberProducer : Producer<int>
{
public RandomNumberProducer()
: base()
{
rand = new Random();
}
private Random rand;
protected override int ProduceNext()
{
return rand.Next();
}
}
class RandomNumberConsumer : Consumer<int>
{
public RandomNumberConsumer(RandomNumberProducer p)
: base(p)
{
}
private static int counter = 0;
private int id = ++counter;
protected override void Consume(int t)
{
Console.Out.WriteLine("#{0}: consumed {1}", id, t);
}
}
static void Main(string[] args)
{
RandomNumberProducer p = new RandomNumberProducer();
RandomNumberConsumer c1 = new RandomNumberConsumer(p);
RandomNumberConsumer c2 = new RandomNumberConsumer(p);
RandomNumberConsumer c3 = new RandomNumberConsumer(p);
p.BeginProduction();
c1.BeginConsumption();
c2.BeginConsumption();
c3.BeginConsumption();
Thread.Sleep(2500);
c3.EndConsumption();
c2.EndConsumption();
c1.EndConsumption();
p.EndProduction();
}
}
}