等待多个不同的脉冲事件

Waiting on multiple different pulses events

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

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

快速而肮脏的解决方案是在单独的对象上执行等待和脉冲,并让使用者线程在继续之前检查其数据集中的更改。似乎没有一种方法可以让一个线程等待两个对象,而不用更强大的线程工具(线程池、任务等)替换通用线程,除非我没有 google 正确的事情.

如果您愿意进行一些重构,我建议您从 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() 调用的重置事件的索引。