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ボタンをクリックすると、アイテムが1つだけ追加され、そのアイテムがループを実行し続けるため、ウィンドウにDequeue多くの"Waiting for signal."印刷物が表示されることです.OutputVisual Studio

メソッドで停止しないのはなぜですか?なぜ常に実行されているのです_workerWaitSignal.WaitOne();か?DoWork()

4

3 に答える 3

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

私はコードを完全には読んでいませんが、(明示的に呼び出すまで設定されたままになる)ではなく(リリースAutoResetEvent後に自動的にリセットされる)を使用するつもりだったと推測できます。WaitOne()ManualResetEventReset()

また、.NETを使用していない理由はありますBlockingCollection<T>か?これは生産者/消費者パターンのフレームワーク実装であり、非常にうまく機能します。

于 2012-11-28T16:19:57.360 に答える
0

いくつかの問題:

  1. 待機を実行した後に「発行待ち」を出力することはほとんど意味がありません。実際の待機のに書き込みを移動することを検討してください。
  2. を使用していますManualResetEvent— その名前が示すように、シグナル状態から戻すには手動でリセットする必要があります。ただし、コード内に呼び出しが表示されません。Reset
  3. 他の同時実行の問題 (たとえば、別の作業項目をエンキューした後に他のスレッドがイベントを設定している間にイベントをリセットするときの競合状態) を回避するには、代わりにシナリオにセマフォを使用することを検討してください。
于 2012-11-28T16:18:02.410 に答える