2013-02-25 2 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에 따라 처음 신호 된 이벤트 만 반환합니다.

자동 응답 이벤트를 폴링하지 않고 적절한 방법으로 수행하는 방법에 대한 아이디어가 있으십니까?

+0

오버로드 된 메서드 중 하나를 사용하십시오. 그리고 do-while을 입력하기 전에 배열을 만들려고 시도하십시오. 어쩌면 새로운 통찰력을 얻을 수 있습니다. –

+0

취소 이벤트가 발생하는 경우 이것이 어떻게 작동하는지 이해할 수 없습니까? – LukeHennerley

+1

cancel 이벤트가 발생하면 주어진 waitHandles에 대한 대기가 – Harry13

답변

1

나는 당신의 방법이 올바르게 쓰여야한다고 생각한다.

내가 WaitHandle.WaitAny()가 the Windows API function WaitForMultipleObjects() 사용하는 생각, 문서가있는 말합니다 :

수정은 그 신호 상태 함수가 반환의 원인이 된 개체 또는 개체에 대해 발생합니다.

사실이면 코드가 작동해야 함을 의미합니다.

테스트 프로그램을 작성했습니다. AutoResetEvents로드를 생성하고 CancelableWaitAll()을 호출하기 전에 그 중 절반을 설정합니다. 그런 다음 AutoResetEvents의 나머지 절반을 설정하기 전에 5 초 동안 대기하는 스레드를 시작합니다. 이 스레드를 시작하면 즉시 주 스레드는 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()를 호출하여 직접 호출 할 수 있습니다.