等待多个不同的脉冲事件

时间:2016-09-27 16:11:14

标签: c# multithreading producer-consumer

我已经获得了一个归结为生产者 - 消费者模式的应用程序。几个线程正在做一些工作并更新单个数据集,以便多个线程可以使用这些数据并自己使用它。目前,它并不是非常复杂,所有消费线程都在数据集上等待,直到其中一个生产者调用一个脉冲。

现在希望任何一个集合发生变化时,其中一个消费者线程会从两个不同的数据集中消耗。团队希望将重构保持在最低限度,而我在线程方面的有限经验给了我一些寻找干净解决方案的问题。

快速而肮脏的解决方案是在单独的对象上进行等待和脉冲,并让用户线程在继续之前检查其数据集中的更改。似乎没有办法让一个线程在两个对象上等待,而不用更强大的线程工具(线程池,任务等)替换通用线程,除非我没有谷歌正确的东西。

1 个答案:

答案 0 :(得分:3)

如果您愿意进行一些重构,我建议您从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();
}

或者您可能希望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();
}

1个事件可以唤醒多个线程,通过一个线程处理多个事件

ManualResetEvent resetEvent0 = ...
ManualResetEvent resetEvent1 = ...

public int WaitForEvent()
{
    int i = WaitHandle.WaitAny(new WaitHandle[] {resetEvent0, resetEvent1});
    return i;
}

i将是调用Set()的重置事件的索引。