1

WaitAny()文档说:

如果在调用期间有多个对象被发出信号,则返回值是所有发出信号对象中索引值最小的发出信号对象的数组索引。

换句话说,它不会“公平”地对待句柄,即选择一个发出时间最长的信号(我猜是一厢情愿),或者至少,只是选择一个随机发出信号的,这样随着时间的推移,公平性至少是统计提供。

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

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

但是没有更聪明的方法可以做到这一点吗?

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

4

1 回答 1

0

事实证明,无需分配数组即可轻松实现。

  1. 手动调用handles[i].WaitOne(0)i每次以不同的迭代顺序。在第一个返回的调用处中断true
  2. 如果所有WaitOne()调用都返回false,请执行WaitAny(handles, timeout)

感谢@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);
}

注意我当前的用例是单线程消费者,因此我没有费心让它线程安全。

于 2014-06-08T22:59:37.993 回答