我已经制作了这个生产者 - 消费者样本,但我不知道为什么它最终冻结了。 问题出在哪儿?如果我在行setNum(-99)处设置断点;然后在休息后继续它完成好。 还请告诉我这段代码是否正常且线程安全。它必须像那样工作,所以同时消费者正在处理它的给定值,必须忽略来自生产者的所有其他值。 我是多线程的新手。
class Program
{
delegate void SetNumberDelegate(int number);
static void Main(string[] args)
{
Random rnd = new Random();
ConsumerClass consumerClass = new ConsumerClass();
SetNumberDelegate setNum = new SetNumberDelegate(consumerClass.setNumber);
Thread.Sleep(20);
int num;
int count = 0;
Console.WriteLine("Start");
while (count++ < 100)
{
num = rnd.Next(0, 100);
Console.WriteLine("Generated number {0}", num);
if (num > 30)
{
setNum(num);
}
}
setNum(-99);
Console.WriteLine("End");
Console.ReadKey();
}
}
class ConsumerClass : IDisposable
{
private int number;
private object locker = new object();
private EventWaitHandle _wh = new AutoResetEvent(false);
private Thread _consumerThread;
public ConsumerClass()
{
number = -1;
_consumerThread = new Thread(consumeNumbers);
_consumerThread.Start();
}
public void Dispose()
{
setNumber(-99);
_consumerThread.Join();
_wh.Close();
}
public void setNumber(int num)
{
if (Monitor.TryEnter(locker))
{
try
{
number = num;
Console.WriteLine("Setting number {0}", number);
}
finally
{
// Ensure that the lock is released.
Monitor.Exit(locker);
}
_wh.Set();
}
}
public void consumeNumbers()
{
while (true)
{
Monitor.Enter(locker);
if (number > -1)
{
try
{
Console.WriteLine("Processing number:{0}", number);
// simulate some work with number e.g. computing and storing to db
Thread.Sleep(20);
Console.WriteLine("Done");
number = -1;
}
finally
{
Monitor.Exit(locker);
}
}
else
{
if (number == -99)
{
Console.WriteLine("Consumer thread exit");
return;
}
Monitor.Exit(locker);
_wh.WaitOne(); // No more tasks - wait for a signal
}
}
}
}
答案 0 :(得分:2)
像这样重写setNumber来查看你的问题:
public void setNumber(int num) {
if (Monitor.TryEnter(locker)) {
// etc..
}
else Console.WriteLine("Number {0} will never make it to the consumer", num);
}
您必须阻止,等待消费者准备好消费或使用队列。
答案 1 :(得分:0)
Monitor.TryEnter(locker);
通常会失败(包括-99),因此您不会设置相当数量的值,这就是设置语句中缺少输出的原因。这是因为它不会等待获取它只会返回false的锁。
答案 2 :(得分:0)
问题似乎出现在代码的最后部分。执行此操作时,您持有锁:
else
{
if (number == -99)
{
Console.WriteLine("Consumer thread exit");
return;
}
Monitor.Exit(locker);
_wh.WaitOne(); // No more tasks - wait for a signal
}
因此,如果number == 99
,该方法将返回而不释放锁。
您的ConsumeNumbers
方法过于复杂。你可以简化它:
while (true)
{
_wh.WaitOne();
lock (locker)
{
if (number == -99)
break;
if (number > -1)
{
// process the number.
number = -1;
}
}
}
这将做同样的事情,而且代码更简单。
顺便说一句,构造:
lock (locker)
{
// do stuff here
}
与:
相同Monitor.Enter(locker);
try
{
// do stuff here
}
finally
{
Monitor.Exit(locker);
}