如何使WaitHandle.WaitAny不优先处理索引较小的句柄?

时间:2014-06-06 00:18:11

标签: .net multithreading waithandle

WaitAny() docs说:

  

如果在通话过程中有多个对象发出信号,则返回   value是具有最小值的信号对象的数组索引   所有信号对象的索引值。

换句话说,它不会“公平地”处理句柄,即选择最长时间的一个信号(我猜是一厢情愿)或至少选择随机信号,以便随着时间的推移,公平至少在统计上提供。

我当然可以在每次通话时为WaitAny()提供我的等待句柄列表(循环或随机)的不同排列:

public static int WaitAnyFair(this WaitHandle[] handles)
{
    return WaitHandle.WaitAny(Shuffle(handles));
}

但是,有没有更聪明的方法呢?

(最初,我正在检查BlockingCollection.TryTakeFromAny()方法是否合理。因为它们基于WaitHandle.WaitAny,它们也不公平。)

1 个答案:

答案 0 :(得分:0)

无需分配数组即可轻松实现。

  1. 每次以不同的迭代顺序手动调用handles[i].WaitOne(0)而不是i。在第一次调用时返回true
  2. 如果所有WaitOne()次来电回复false,请执行WaitAny(handles, timeout)
  3. 感谢@RaymondChen的想法。

    private static int _lastWaitAnyMoreFairStartIndex;
    
    public static int WaitAnyMoreFair(WaitHandle[] handles, TimeSpan timeout)
    {
        // increment, but prevent from wrapping negative,
        // as that would break the modulo indexing
        if (++_lastWaitAnyMoreFairStartIndex < 0)
            _lastWaitAnyMoreFairStartIndex = 0;
    
        for (int i = 0; i < handles.Length; i++)
        {
            var index = (i + _lastWaitAnyMoreFairStartIndex) % handles.Length;
            if (handles[index].WaitOne(0))
                return index;
        }
    
        return WaitHandle.WaitAny(handles, timeout);
    }
    

    N.B。我目前的用例是单线程消费者,因此我没有费心去做线程安全。