C # WaitHandle cancelable WaitAll

I have the following code that aims to wait for all given wait commands, but can be overridden by a specific wait descriptor:

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; } 

This only works for ManualReset events. When using events, AutoReset WaitAny resets all alarm events, but returns only the first signal (according to MSDN).

Any ideas how to do this with AutoReset events appropriately without polling?

+6
source share
1 answer

I think your method should work correctly as written.

I believe WaitHandle.WaitAny () uses the Windows API function WaitForMultipleObjects () , the documentation that says:

Modification occurs only for the object or objects whose alarm state caused a return of the function.

If true, that means your code should work.

I wrote a test program. It creates an AutoResetEvents download and sets half of them before calling CancelableWaitAll (). Then it starts a thread that waits 5 seconds before installing the other half of AutoResetEvents. Immediately after starting this thread, the main thread calls CancelableWaitAll ().

If WaitAny () actually reset any of the autosave events other than whose index was returned, CancelableWaitAll () will never return.

Since it returns (after 5 seconds, of course), I claim that your code works with 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; } } } 

Unfortunately, I cannot prove that WaitHandle.WaitAll () uses WaitForMultipleObjects (). However, if this is not the case, you can call it yourself using WaitHandle.SafeWaitHandle to access the OS event windows and use P / Invoke to call WaitForMultipleObjects ().

+1
source

All Articles