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(在某些
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());
}