C#一旦主线程睡眠,所有线程都停止
我有一个课程运行生产者-消费者模型,如下所示:C#一旦主线程睡眠,所有线程都停止,c#,multithreading,.net-2.0,C#,Multithreading,.net 2.0,我有一个课程运行生产者-消费者模型,如下所示: public class SyncEvents { public bool waiting; public SyncEvents() { waiting = true; } } public class Producer { private readonly Queue<Delegate> _queue; private SyncEvents _sync; pr
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);
}
}
公共类同步事件
{
公共布尔等待;
公共事件()
{
等待=真;
}
}
公共级制作人
{
专用只读队列_队列;
私有同步事件_sync;
私有对象_waitAck;
公共生产者(队列q、同步事件同步、对象obj)
{
_队列=q;
_同步=同步;
_waitAck=obj;
}
public void ThreadRun()
{
锁定(同步)
{
while(true)
{
监视器。等待(_sync,0);
如果(_queue.Count>0)
{
_sync.waiting=false;
}
其他的
{
_sync.waiting=true;
锁(_waitAck)
{
监视器脉冲(_waitAck);
}
}
监视器脉冲(同步);
}
}
}
}
公共类消费者
{
专用只读队列_队列;
私有同步事件_sync;
私有整数计数=0;
公共使用者(队列q、同步事件同步)
{
_队列=q;
_同步=同步;
}
public void ThreadRun()
{
锁定(同步)
{
while(true)
{
而(_queue.Count==0)
{
监视器。等待(_sync);
}
委托查询=_queue.Dequeue();
query.DynamicInvoke(null);
计数++;
监视器脉冲(同步);
}
}
}
}
///
///充当DataGridViewCustomCell生成的查询的使用者
///
公共类查询读取
{
私有SyncEvents_SyncEvents=新SyncEvents();
私有对象waitAck=新对象();
专用队列_queryQueue=新队列();
生产者、查询者、生产者;
消费者查询消费者;
公共查询读取()
{
queryProducer=新生产者(_queryQueue,_syncEvents,waitAck);
queryConsumer=新消费者(\u queryQueue,\u syncEvents);
Thread producerThread=新线程(queryProducer.ThreadRun);
Thread consumerThread=新线程(queryConsumer.ThreadRun);
producerThread.IsBackground=true;
consumerThread.IsBackground=true;
producerThread.Start();
consumerThread.Start();
}
公共bool isQueueEmpty()
{
return\u syncEvents.waiting;
}
公共无效等待()
{
锁(等待)
{
而(_queryQueue.Count>0)
{
监视器。等待(等待);
}
}
}
公共无效排队(委托项)
{
_queryQueue.Enqueue(项目);
}
}
代码运行平稳,但wait()函数无效。
在某些情况下,我希望等待队列中的所有函数都完成运行,因此我创建了wait()函数
生产者将在适当的时间触发waitAck脉冲
但是,当在Wait()函数中运行行“Monitor.Wait(waitAck);”时,所有线程都会停止,包括生产者线程和消费者线程
为什么会发生这种情况?我如何解决?谢谢 所有线程实际上都不太可能停止,尽管我应该指出,为了避免错误唤醒,您可能应该使用while循环而不是if语句:
lock (waitAck)
{
while(queryProducer.secondQueue.Count > 0)
{
Monitor.Wait(waitAck);
}
}
您正在调用Monitor.Wait
这一事实意味着应该释放waitAck
,这样就不会阻止使用者线程锁定
您能否提供更多关于生产者/消费者线程“停止”方式的信息?他们看起来是不是僵持了
您的制作人是否正在使用Notify
或NotifyAll
?你现在有一个额外的等待线程,所以如果你只使用Notify
它只会释放一个线程。。。如果没有生产者
和消费者
类的详细信息,很难看出这是否是一个问题
如果你能展示一个简短但完整的程序来演示这个问题,那会有所帮助
编辑:好的,现在你已经发布了代码,我可以看到一些问题:
- 拥有如此多的公共变量会导致灾难。您的类应该封装它们的功能,以便其他代码不必到处寻找实现的细节。(例如,此处的调用代码实际上不应该访问队列。)
- 您将项目直接添加到第二个队列,这意味着您无法有效地唤醒制作人将其添加到第一个队列。为什么会有多个队列
- 您总是在生产者线程中等待
。。。为什么?从什么开始呢?一般来说,生产者线程不应该等待,除非您有一个有界缓冲区\u sync
- 您有一个静态变量(_waitAck),每次创建新实例时都会覆盖该变量。那是个坏主意
SyncEvents
类-这意味着要做一些有趣的事情吗
老实说,看起来你有一个很奇怪的设计——你最好从头开始。尝试将整个生产者/消费者队列封装在一个类中,该类具有
product
和Consume
方法,以及waitforepty
(或类似的东西)。我想通过这种方式,您会发现同步逻辑更加简单。以下是我对您的代码的看法:
public class ProducerConsumer
{
private ManualResetEvent _ready;
private Queue<Delegate> _queue;
private Thread _consumerService;
private static Object _sync = new Object();
public ProducerConsumer(Queue<Delegate> queue)
{
lock (_sync)
{
// Note: I would recommend that you don't even
// bother with taking in a queue. You should be able
// to just instantiate a new Queue<Delegate>()
// and use it when you Enqueue. There is nothing that
// you really need to pass into the constructor.
_queue = queue;
_ready = new ManualResetEvent(false);
_consumerService = new Thread(Run);
_consumerService.IsBackground = true;
_consumerService.Start();
}
}
public override void Enqueue(Delegate value)
{
lock (_sync)
{
_queue.Enqueue(value);
_ready.Set();
}
}
// The consumer blocks until the producer puts something in the queue.
private void Run()
{
Delegate query;
try
{
while (true)
{
_ready.WaitOne();
lock (_sync)
{
if (_queue.Count > 0)
{
query = _queue.Dequeue();
query.DynamicInvoke(null);
}
else
{
_ready.Reset();
continue;
}
}
}
}
catch (ThreadInterruptedException)
{
_queue.Clear();
return;
}
}
protected override void Dispose(bool disposing)
{
lock (_sync)
{
if (_consumerService != null)
{
_consumerService.Interrupt();
}
}
base.Dispose(disposing);
}
}
如果不知道其他两个类的代码,我就说不出来。@LiKaShing先生请告诉我我的解决方案是否有助于您清理整个问题。这是我为我的另一个项目编写的非常简单和干净的代码,经过一些修改,我让它做了你似乎感兴趣的事情
public class ProducerConsumer
{
private bool _canEnqueue;
private ManualResetEvent _ready;
private Queue<Delegate> _queue;
private Thread _consumerService;
private static Object _sync = new Object();
private static ManualResetEvent _wait = new ManualResetEvent(false);
public ProducerConsumer()
{
lock (_sync)
{
_queue = new Queue<Delegate> _queue;
_canEnqueue = true;
_ready = new ManualResetEvent(false);
_consumerService = new Thread(Run);
_consumerService.IsBackground = true;
_consumerService.Start();
}
}
public bool Enqueue(Delegate value)
{
lock (_sync)
{
// Don't allow anybody to enqueue
if( _canEnqueue )
{
_queue.Enqueue(value);
_ready.Set();
return true;
}
}
// Whoever is calling Enqueue should try again later.
return false;
}
// The consumer blocks until the producer puts something in the queue.
private void Run()
{
try
{
while (true)
{
// Wait for a query to be enqueued
_ready.WaitOne();
// Process the query
lock (_sync)
{
if (_queue.Count > 0)
{
Delegate query = _queue.Dequeue();
query.DynamicInvoke(null);
}
else
{
_canEnqueue = true;
_ready.Reset();
_wait.Set();
continue;
}
}
}
}
catch (ThreadInterruptedException)
{
_queue.Clear();
return;
}
}
// Block your queue from enqueuing, return null
// if the queue is already empty.
public ManualResetEvent BlockQueue()
{
lock(_sync)
{
if( _queue.Count > 0 )
{
_canEnqueue = false;
_wait.Reset();
}
else
{
// You need to tell the caller that they can't
// block your queue while it's empty. The caller
// should check if the result is null before calling
// WaitOne().
return null;
}
}
return _wait;
}
protected override void Dispose(bool disposing)
{
lock (_sync)
{
if (_consumerService != null)
{
_consumerService.Interrupt();
// Set wait when you're disposing the queue
// so that nobody is left with a lingering wait.
_wait.Set();
}
}
base.Dispose(disposing);
}
}