2013-02-25 34 views
6

我有下面的代码,有目标,以等待所有给定的等待句柄,而是由特定的等待句柄撤销:C#的WaitHandle取消了WaitAll

public static bool CancelableWaitAll(WaitHandle[] waitHandles, WaitHandle cancelWaitHandle) 
{ 
    var waitHandleList = new List<WaitHandle>(); 
    waitHandleList.Add(cancelWaitHandle); 
    waitHandleList.AddRange(waitHandles); 
    int handleIdx; 
    do 
    { 
     handleIdx = WaitHandle.WaitAny(waitHandleList.ToArray()); 
     waitHandleList.RemoveAt(handleIdx); 
    } 
    while (waitHandleList.Count > 1 && handleIdx != 0); 
    return handleIdx != 0; 
} 

这仅适用于ManualReset事件。使用AutoReset事件时,WaitAny会重置所有发送信号的事件,但仅返回第一个发送信号的事件(根据MSDN)。

任何想法如何使用AutoReset事件以正确的方式完成此操作而无需轮询?

+0

尝试使用其中一种重载方法。并尝试在进入do-while之前创建该阵列,也许你会获得新的见解。 – 2013-02-25 14:45:14

+0

我无法理解,如果取消事件发生,这将如何工作? – LukeHennerley 2013-02-25 14:46:22

+1

如果取消事件发生,等待所有给定的waitHandles被取消 – Harry13 2013-02-25 14:51:36

回答

1

我认为你的方法应该按照书面方式正确工作。

我相信WaitHandle.WaitAny()使用the Windows API function WaitForMultipleObjects(),该文档它说:只为一个或多个对象,其信号状态导致函数返回时

修改。

如果为true,则表示您的代码应该工作。

我写了一个测试程序。它会在调用CancelableWaitAll()之前创建一个AutoResetEvents负载并设置其中的一半。然后它启动一个等待5秒的线程,然后设置AutoResetEvents的另一半。在启动该线程后,主线程立即调用CancelableWaitAll()。

如果WaitAny()实际上重置了索引被返回的事件之外的任何自动重置事件,那么CancelableWaitAll()将永远不会返回。

由于它返回(5秒,当然后),我断言你的代码与AutoResetEvents:

using System; 
using System.Collections.Generic; 
using System.Threading; 
using System.Threading.Tasks; 

namespace Demo 
{ 
    public static class Program 
    { 
     private static void Main(string[] args) 
     { 
      AutoResetEvent[] events = new AutoResetEvent[32]; 

      for (int i = 0; i < events.Length; ++i) 
      { 
       events[i] = new AutoResetEvent(false); 
      } 

      // Set the first 16 auto reset events before calling CancelableWaitAll(). 

      for (int i = 0; i < 16; ++i) 
      { 
       events[i].Set(); 
      } 

      // Start a thread that waits five seconds and then sets the rest of the events. 

      Task.Factory.StartNew(() => setEvents(events)); 

      Console.WriteLine("Waiting for all events to be set."); 

      ManualResetEvent stopper = new ManualResetEvent(false); 
      CancelableWaitAll(events, stopper); 

      Console.WriteLine("Waited."); 
     } 

     private static void setEvents(AutoResetEvent[] events) 
     { 
      Thread.Sleep(5000); 

      for (int i = 16; i < events.Length; ++i) 
      { 
       events[i].Set(); 
      } 
     } 

     public static bool CancelableWaitAll(WaitHandle[] waitHandles, WaitHandle cancelWaitHandle) 
     { 
      var waitHandleList = new List<WaitHandle>(); 
      waitHandleList.Add(cancelWaitHandle); 
      waitHandleList.AddRange(waitHandles); 
      int handleIdx; 
      do 
      { 
       handleIdx = WaitHandle.WaitAny(waitHandleList.ToArray()); 
       waitHandleList.RemoveAt(handleIdx); 
      } 
      while (waitHandleList.Count > 1 && handleIdx != 0); 
      return handleIdx != 0; 
     } 
    } 
} 

不幸的是,我不能证明WaitHandle.WaitAll的()使用WaitForMultipleObjects的( )。但是,如果没有,可以使用WaitHandle.SafeWaitHandle来获取OS事件句柄并使用P/Invoke来调用WaitForMultipleObjects(),您可以自己调用它。