phi*_*ill 3 c# multithreading producer-consumer
我得到了一个可以归结为生产者-消费者模式的应用程序。几个线程正在做一些工作并更新单个数据集,以便更多线程可以使用该数据并使用它做自己的工作。目前,它并不是非常复杂,所有消费线程都在等待数据集,直到其中一个生产者调用一个pulseall。
现在希望有一个消费者线程在任何一组更改时从两个不同的数据集消费。团队希望将重构保持在最低限度,而我有限的线程经验让我在寻找干净的解决方案时遇到了一些问题。
快速而肮脏的解决方案是在单独的对象上进行等待和脉冲,并让消费者线程在继续之前检查其数据集中的更改。似乎没有一种方法可以让一个线程等待两个对象,而不用更强大的线程工具(线程池、任务等)替换通用线程,除非我没有找到正确的东西。
如果您愿意进行一些重构,我建议您从 Monitor 切换到EventWaitHandle派生类之一。
根据您可能想要的行为AutoResetEvent,这将更接近于Monitor.Entier(obj)/Monitor.Exit(obj)
private readonly object _lockobj = new Object();
public void LockResource()
{
Monitor.Enter(_lockobj);
}
public void FreeResource()
{
Monitor.Exit(_lockobj);
}
//Which is the same as
private readonly AutoResetEvent _lockobj = new AutoResetEvent(true);
public void LockResource()
{
_lockobj.WaitOne();
}
public void FreeResource()
{
_lockobj.Set();
}
Run Code Online (Sandbox Code Playgroud)
或者你可能想要ManualResetEvent更紧密地表现得像Monitor.Wait(obj)/Monitor.PulseAll(obj)
private readonly object _lockobj = new Object();
public void LockResource()
{
Monitor.Enter(_lockobj);
}
public bool WaitForResource()
{
//requires to be inside of a lock.
//returns true if it is the lock holder.
return Monitor.Wait(_lockobj);
}
public void SignalAll()
{
Monitor.PulseAll(_lockobj);
}
// Is very close to
private readonly ManualResetEvent _lockobj = new ManualResetEvent(true);
public bool LockResource()
{
//Returns true if it was able to perform the lock.
return _lockobj.Reset();
}
public void WaitForResource()
{
//Does not require to be in a lock.
//if the _lockobj is in the signaled state this call does not block.
_lockobj.WaitOne();
}
public void SignalAll()
{
_lockobj.Set();
}
Run Code Online (Sandbox Code Playgroud)
1个事件可以唤醒多个线程,可以通过一个线程处理多个事件
ManualResetEvent resetEvent0 = ...
ManualResetEvent resetEvent1 = ...
public int WaitForEvent()
{
int i = WaitHandle.WaitAny(new WaitHandle[] {resetEvent0, resetEvent1});
return i;
}
Run Code Online (Sandbox Code Playgroud)
并且i将是Set()调用它的重置事件的索引。