1

我有一个如下的生产者-消费者类。

public class ProducerConsumer<T> where T : class
    {
        private Thread _workerThread;
        private readonly Queue<T> _workQueue;
        private readonly object _lockObject = new object();
        private readonly Action<T> _workCallbackAction;
        private ManualResetEvent _workerWaitSignal;

        public ProducerConsumer(Action<T> action)
        {               
            _workCallbackAction = action;
            _workQueue = new Queue<T>();                
        }

        private void DoWork()
        {
            while (true)
            {
                T workItemToBeProcessed = default(T);
                bool hasSomeWorkItem = false;

                lock (_lockObject)
                {
                    hasSomeWorkItem = _workQueue.Count > 0;

                    if (hasSomeWorkItem)
                    {
                        workItemToBeProcessed = _workQueue.Dequeue();
                        if (workItemToBeProcessed == null)
                        {
                            return;
                        }
                    }
                }
                if (hasSomeWorkItem)
                {
                    if (_workCallbackAction != null)
                    {
                        _workCallbackAction(workItemToBeProcessed);
                    }
                }
                else
                {
                    _workerWaitSignal.WaitOne();
                    Debug.WriteLine("Waiting for signal.");
                }
            }
        }

        public void EnQueueWorkItem(T workItem)
        {
            lock (_lockObject)
            {
                _workQueue.Enqueue(workItem);
                _workerWaitSignal.Set();
            }
        }

        public void StopWork(ManualResetEvent stopSignal)
        {
            EnQueueWorkItem(null);
            _workerThread.Join();
            _workerWaitSignal.Close();
            _workerWaitSignal = null;
            if (stopSignal != null)
            {
                stopSignal.Set();
            }
        }

        public void ReStart()
        {
            _workerWaitSignal = new ManualResetEvent(false);
            _workerThread = new Thread(DoWork) { IsBackground = true };
            _workerThread.Start();
        }
    }

我正在通过以下方式使用它:

 public partial class Form1 : Form
    {

        private RecordProducerConsumer<string> _proConsumer;
        public Form1()
        {
            InitializeComponent();
            _proConsumer = new RecordProducerConsumer<string>(DoAction);
        }


        private bool restart=true;
        private int item = 0;

        private void button1_Click(object sender, EventArgs e)
        {

            if (restart)
            {
                _proConsumer.ReStart();
                restart = false;
            }

            item++;
            _proConsumer.EnQueueWorkItem(item.ToString());

        }

        private void DoAction(string str)
        {
            Debug.WriteLine(str);
        }

        private void btnStop_Click(object sender, EventArgs e)
        {
            ManualResetEvent mre = new ManualResetEvent(false);
            _proConsumer.StopWork(mre);
            mre.WaitOne();
            restart = true;
        }

        private void Stop(ManualResetEvent mre)
        {
            mre.WaitOne();          
        }
    }

我的问题或我无法理解的是,当我单击按钮Start时,我只添加一个项目,并且Dequeue该项目但继续运行循环,因此我在."Waiting for signal."OutputVisual Studio

为什么它不停止_workerWaitSignal.WaitOne();DoWork()方法中,为什么它一直在运行?

4

3 回答 3

0

几个问题:

  1. 执行等待输出“等待问题”几乎没有任何意义。考虑在实际等待之前移动写入。
  2. 您正在使用ManualResetEvent- 顾名思义,它需要手动重置才能从信号状态恢复。Reset但是,我在您的代码中看不到调用。
  3. 为避免其他并发问题(例如,在重置事件时出现竞争条件,而其他线程在将另一个工作项入队后设置事件),请考虑在您的场景中使用信号量
于 2012-11-28T16:18:02.410 回答
0

试试这个......我可能是错的......但这就是我通过阅读你的代码所能弄清楚的。希望这可以帮助 :)

 private void button1_Click(object sender, EventArgs e)
    {

        if (restart)
        {
            restart = false;
            _proConsumer.ReStart();                
        }

        item++;
        _proConsumer.EnQueueWorkItem(item.ToString());

    }
于 2012-11-28T16:19:48.000 回答
0

我没有彻底阅读代码,但我可以大胆猜测您打算使用 an AutoResetEvent(在某些WaitOne()版本发布后会自动重置)而不是 a ManualResetEvent(在您明确调用之前保持设置Reset())。

另外,您有什么理由不使用 .NET 的BlockingCollection<T>吗?它是生产者/消费者模式的框架实现,效果很好。

于 2012-11-28T16:19:57.360 回答