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);
    }
}