C# 一旦主线程休眠,所有线程停止

标签 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;
    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 它只会释放一个线程......如果没有你的 ProducerConsumer 类。

如果您能展示一个简短但完整的程序来演示问题,那将会有所帮助。

编辑:好的,现在您已经发布了代码,我可以看到一些问题:

  • 拥有如此多的公共(public)变量是灾难的根源。您的类应该封装它们的功能,这样其他代码就不必四处寻找实现的点点滴滴。 (例如,您在此处的调用代码实际上不应该访问队列。)

  • 您将项目直接添加到第二个队列,这意味着您无法有效地唤醒生产者以将它们添加到第一个队列。为什么你甚至有多个队列?

  • 您总是在生产者线程中等待 _sync...为什么?什么会通知它开始?一般来说,生产者线程不必等待,除非你有一个有界缓冲区

  • 您有一个静态 变量 (_waitAck),每次您创建一个新实例时它都会被覆盖。这是个坏主意。

您还没有显示您的 SyncEvents 类 - 这意味着要做什么有趣的事情吗?

老实说,您的设计似乎很奇怪 - 您最好从头开始。尝试将整个生产者/消费者队列封装在一个类中,该类具有 ProduceConsume 方法,以及 WaitForEmpty(或类似的东西那)。我想您会发现这样同步逻辑会容易得多。

关于C# 一旦主线程休眠,所有线程停止,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2294485/

相关文章:

java - 使用多线程实现java gui登录

java - 以下代码运行时是否会导致死锁

C++工作队列与阻塞

c# - 如何检查当前操作是否在对象范围内?

c# - 如何在 MenuItem 中放置图标

c# - C# 中的 override 和 new 关键字有什么区别?

c# - 使用 SHA256 key 的哈希字符串

asp.net - 从 ASP.NET 2.0 成员身份解密 'Encrypted' 密码

monitoring - 如何使用 C# 从 Bios 获取 CPU 温度信息?

c# - 禁用 DataGridView 中的自动添加行