为什么这条消费者-生产者的线被冻结了
本文关键字:冻结 结了 生产者 消费者 为什么 | 更新日期: 2023-09-27 18:09:06
我制作了这个生产者-消费者样本,但我不知道为什么它最后会冻结。问题在哪里?如果我在setNum(-99)行设置一个断点;休息后继续,就完成了。也请告诉我这个代码是ok的和线程安全的。它必须这样工作,所以在消费者处理其给定值的同时,必须忽略来自生产者的所有其他值。我对多线程很陌生。
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
}
}
}
}
像这样重写setNumber来查看问题:
public void setNumber(int num) {
if (Monitor.TryEnter(locker)) {
// etc..
}
else Console.WriteLine("Number {0} will never make it to the consumer", num);
}
你必须阻塞,等待消费者准备好消费或使用队列。
Monitor.TryEnter(locker);
通常会失败(包括-99),因此您不会设置相当数量的值,这就是设置语句中缺少输出的原因。这是因为它不会等待获取锁,它只会返回false。
问题似乎出现在代码的最后一部分。当你执行this时,你持有锁:
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);
}