C#生产者/消费者实施问题

C#生产者/消费者实施问题,c#,C#,我有一个生产者和消费者分类如下 public class ProducerConsumer<T> where T : class { private Thread _workerThread; private readonly Queue<T> _workQueue; private readonly object _lockObject = new object(); private readonl

我有一个生产者和消费者分类如下

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();
        }
    }
公共类生产者消费者,其中T:class
{
私有线程\u workerThread;
专用只读队列\u工作队列;
私有只读对象_lockObject=新对象();
私有只读操作\u workCallbackAction;
专用手动复位事件\u WorkerWait信号;
公共生产者消费者(行动)
{               
_workCallbackAction=操作;
_工作队列=新队列();
}
私房
{
while(true)
{
T workItemToBeProcessed=默认值(T);
bool hasSomeWorkItem=false;
锁定(锁定对象)
{
hasSomeWorkItem=\u workQueue.Count>0;
if(hasSomeWorkItem)
{
workItemToBeProcessed=_workQueue.Dequeue();
if(workItemToBeProcessed==null)
{
返回;
}
}
}
if(hasSomeWorkItem)
{
if(_workCallbackAction!=null)
{
_workCallbackAction(workItemToBeProcessed);
}
}
其他的
{
_workerWaitSignal.WaitOne();
Debug.WriteLine(“等待信号”);
}
}
}
公共无效排队工作项(T工作项)
{
锁定(锁定对象)
{
_workQueue.Enqueue(workItem);
_workerWaitSignal.Set();
}
}
公共无效停止作业(手动重置事件停止信号)
{
排队工作项(空);
_workerThread.Join();
_workerWaitSignal.Close();
_workerWaitSignal=null;
if(停止信号!=null)
{
stopSignal.Set();
}
}
公共无效重新启动()
{
_workerWaitSignal=新手动复位事件(假);
_workerThread=新线程(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();          
        }
    }
公共部分类表单1:表单
{
私人记录生产者消费者(proConsumer);;
公共表格1()
{
初始化组件();
_proConsumer=新记录producerconsumer(DoAction);
}
private bool restart=true;
私有int项=0;
私有无效按钮1\u单击(对象发送者,事件参数e)
{
如果(重新启动)
{
_proConsumer.ReStart();
重新启动=错误;
}
项目++;
_proConsumer.EnQueueWorkItem(item.ToString());
}
私有void操作(字符串str)
{
Debug.WriteLine(str);
}
私有void btnStop_单击(对象发送方,事件参数e)
{
ManualResetEvent mre=新的ManualResetEvent(错误);
_采购商停止工作(mre);
韦通先生();
重启=真;
}
专用无效停止(手动重置事件mre)
{
韦通先生();
}
}
我的问题或我无法理解的是,当我单击
Start
按钮时,我只添加了一个项目,它
Dequeue
该项目,但继续运行循环,因此我看到很多
“等待信号”。
visualstudio
中的
输出
窗口上打印输出

为什么它不在
\u workerWaitSignal.WaitOne()上停止
DoWork()
方法中,为什么它一直在运行?

两个问题:

  • 在执行等待后输出“等待问题”几乎没有任何意义。考虑在实际等待之前移动写。
  • 您使用的是
    ManualResetEvent
    ——顾名思义,它需要手动复位才能从信号状态恢复。但是,我在代码中看不到对
    Reset
    的调用
  • 以避免其他并发问题(例如,当重置事件时的竞争条件,而其他线程在排队另一个工作项之后设置事件),请考虑使用A来代替您的方案。

  • 试试这个。。。我可能错了…但这就是我通过阅读你的代码所能理解的。希望这有帮助:)


    我还没有完全阅读代码,但我可以大胆猜测,您打算使用a(在某些
    WaitOne()
    被释放后自动重置),而不是a(在显式调用
    Reset()
    之前保持设置)


    还有,你有什么理由不使用.NET的吗?它是producer/consumer模式的框架实现,工作得非常好。

    我明白了。您可以尝试从参考源复制粘贴,值得一试。
     private void button1_Click(object sender, EventArgs e)
        {
    
            if (restart)
            {
                restart = false;
                _proConsumer.ReStart();                
            }
    
            item++;
            _proConsumer.EnQueueWorkItem(item.ToString());
    
        }