我有一个运行Producer-Consumer模型的类,如下所示:
public class SyncEvents
{
public bool waiting;
public SyncEvents()
{
waiting = true;
}
}
public class Producer
{
private readonly Queue<Delegate> _queue;
private SyncEvents _sync;
private Object _waitAck;
public Producer(Queue<Delegate> q, SyncEvents sync, Object obj)
{
_queue = q;
_sync = sync;
_waitAck = obj;
}
public void ThreadRun()
{
lock (_sync)
{
while (true)
{
Monitor.Wait(_sync, 0);
if (_queue.Count > 0)
{
_sync.waiting = false;
}
else
{
_sync.waiting = true;
lock (_waitAck)
{
Monitor.Pulse(_waitAck);
}
}
Monitor.Pulse(_sync);
}
}
}
}
public class Consumer
{
private readonly Queue<Delegate> _queue;
private SyncEvents _sync;
private int count = 0;
public Consumer(Queue<Delegate> q, SyncEvents sync)
{
_queue = q;
_sync = sync;
}
public void ThreadRun()
{
lock (_sync)
{
while (true)
{
while (_queue.Count == 0)
{
Monitor.Wait(_sync);
}
Delegate query = _queue.Dequeue();
query.DynamicInvoke(null);
count++;
Monitor.Pulse(_sync);
}
}
}
}
/// <summary>
/// Act as a consumer to the queries produced by the DataGridViewCustomCell
/// </summary>
public class QueryThread
{
private SyncEvents _syncEvents = new SyncEvents();
private Object waitAck = new Object();
private Queue<Delegate> _queryQueue = new Queue<Delegate>();
Producer queryProducer;
Consumer queryConsumer;
public QueryThread()
{
queryProducer = new Producer(_queryQueue, _syncEvents, waitAck);
queryConsumer = new Consumer(_queryQueue, _syncEvents);
Thread producerThread = new Thread(queryProducer.ThreadRun);
Thread consumerThread = new Thread(queryConsumer.ThreadRun);
producerThread.IsBackground = true;
consumerThread.IsBackground = true;
producerThread.Start();
consumerThread.Start();
}
public bool isQueueEmpty()
{
return _syncEvents.waiting;
}
public void wait()
{
lock (waitAck)
{
while (_queryQueue.Count > 0)
{
Monitor.Wait(waitAck);
}
}
}
public void Enqueue(Delegate item)
{
_queryQueue.Enqueue(item);
}
}
代码运行顺利但是wait()函数.
在某些情况下,我想等到队列中的所有函数都完成运行,所以我做了wait()函数.
生产者将在适当的时间触发waitAck脉冲.
但是,当行“Monitor.Wait(waitAck);”时在wait()函数中运行,所有线程都停止,包括生产者和消费者线程.
为什么会发生这种情况,我该如何解决?谢谢!
最佳答案 所有线程似乎都不太可能实际停止,尽管我应该指出,为了避免错误唤醒,你应该有一个while循环而不是if语句:
lock (waitAck)
{
while(queryProducer.secondQueue.Count > 0)
{
Monitor.Wait(waitAck);
}
}
您正在调用Monitor.Wait的事实意味着应该释放waitAck,因此它不应该阻止使用者线程锁定…
您能否提供有关生产者/消费者线程“停止”的方式的更多信息?看起来他们刚刚陷入困境吗?
您的制作人是否使用Notify或NotifyAll?你现在有一个额外的等待线程,所以如果你只使用Notify它只会释放一个线程……如果没有你的Producer和Consumer类的细节,很难看出这是否是一个问题.
如果您可以展示一个简短但完整的程序来演示问题,那将有所帮助.
编辑:好的,现在你已经发布了我可以看到许多问题的代码:
>拥有如此多的公共变量是一种灾难.你的类应该封装它们的功能,这样其他代码就不必去寻找实现的部分. (例如,您的调用代码实际上不应该访问队列.)
>您将项目直接添加到第二个队列,这意味着您无法有效唤醒生产者将其添加到第一个队列.为什么你甚至有多个队列?
>你总是在生产者线程中等待_sync …为什么?什么会开始通知它?一般来说,生产者线程不应该等待,除非你有一个有界缓冲区
>您有一个静态变量(_waitAck),每次创建新实例时都会被覆盖.这是个坏主意.
你还没有展示你的SyncEvents类 – 这是否意味着做任何有趣的事情?
说实话,你似乎有一个很奇怪的设计 – 你可能最好从头开始.尝试将整个生产者/消费者队列封装在一个类中,该类具有Produce和Consume方法,以及WaitForEmpty(或类似的东西).我认为你会发现同步逻辑更容易.