编辑:我甚至想问这个问题,也要为暂时的精神错乱辩护,但在当时是有道理的(请参阅下面的编辑2)。

对于.NET 3.5项目,我需要检查两种类型的资源(R1和R2)。每个资源类型在任何时候都可以具有(例如)10个实例。

当这两种类型的资源之一可用时,我的工作线程需要唤醒(线程数量可变)。在较早的实现中,只有一种资源类型,我使用信号量来检查可用性。

现在,我需要等待两个单独的信号量(S1和S2),它们可以跟踪资源的可用性。

WaitHandle[] waitHandles = new WaitHandle[] { s1, s2 };
int signalledHandle = WaitHandle.WaitAny(waitHandles);

switch (signalledHandle)
{
    case 0:
        // Do stuff
        s1.Release();
    case 1:
        // Do stuff
        s2.Release();
}

但是,这有一个问题。从WaitAny的MSDN文档中:



这表明调用WaitAny后,我的信号量计数可能都减少了1。因为signalledHandle将指示s1已发出信号,所以我将开始使用资源R1,并在完成后释放它。但是,由于我不知道是否已发出S2信号,因此该资源的可用性计数现在可能已关闭。如果发生10次,则我的信号量将永久为“空”,并且资源R2将不再使用。

处理此问题的最佳方法是什么?我应该从使用两个信号量切换到简单计数器,然后从AutoResetEvent切换为在任何一个计数器更改时发出信号吗?我是否缺少一些更优雅的方法?

编辑1:
根据Ravadre的说法,WaitAny之后实际上只有一个信号量会被更改。稍微修改他的示例似乎可以证实这一点,但是有没有人可以指出我的一些官方文档来指定这一点呢?

编辑2:
我在回家的路上就在想这个。直到那时,我才意识到这对于WaitAny的任何使用都必须是正确的。这个问题将不仅限于信号量,而是几乎任何类型的同步对象,使得WaitAny实际上是无用的。

最佳答案

如果我正确地理解了您的问题,我认为您的解决方案完全可以,并且您刚刚解释了msdn引用。调用WaitHandle.WaitAny()时,您将获得最低的索引,但是您只能锁定一个waitHandle(在这种情况下为信号灯),请检查以下示例代码:


Semaphore s1 = new Semaphore(1, 2);
Semaphore s2 = new Semaphore(1, 2);

WaitHandle[] handles = new WaitHandle[] { s1, s2 };

int x = WaitHandle.WaitAny(handles);

int prevS1 = s1.Release();
int prevS2 = s2.Release();

在这种情况下,prevS1将等于0,因为信号量s1已“等待”,因此它的计数器已减少为0,而prevS2将等于1,因为自实例化以来它的状态没有改变(Release()方法在释放之前返回计数器,因此返回1表示“原来是1,现在是2”)。

您可能想要查看的另一个资源:http://www.albahari.com/threading/part2.aspx#_Wait_Handles。尽管它不是“官方”资源,但我认为没有理由发现它不可靠。

10-01 03:45