/// <summary> /// Release the work items' wait handles /// </summary> /// <param name="waitableResults">An array of work item results</param> private static void ReleaseWaitHandles(IWaitableResult[] waitableResults) { for (int i = 0; i < waitableResults.Length; ++i) { WorkItemResult wir = (WorkItemResult)waitableResults[i].GetWorkItemResult(); wir.GetWorkItem().ReleaseWaitHandle(); } }
/// <summary> /// Waits for any of the work items in the specified array to complete, cancel, or timeout /// </summary> /// <param name="waitableResults">Array of work item result objects</param> /// <param name="millisecondsTimeout">The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.</param> /// <param name="exitContext"> /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. /// </param> /// <param name="cancelWaitHandle">A cancel wait handle to interrupt the wait if needed</param> /// <returns> /// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled. /// </returns> internal static int WaitAny( IWaitableResult[] waitableResults, int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle) { WaitHandle[] waitHandles; if (null != cancelWaitHandle) { waitHandles = new WaitHandle[waitableResults.Length + 1]; GetWaitHandles(waitableResults, waitHandles); waitHandles[waitableResults.Length] = cancelWaitHandle; } else { waitHandles = new WaitHandle[waitableResults.Length]; GetWaitHandles(waitableResults, waitHandles); } int result = STPEventWaitHandle.WaitAny(waitHandles, millisecondsTimeout, exitContext); // Treat cancel as timeout if (null != cancelWaitHandle) { if (result == waitableResults.Length) { result = STPEventWaitHandle.WaitTimeout; } } ReleaseWaitHandles(waitableResults); return result; }
/// <summary> /// Fill an array of wait handles with the work items wait handles. /// </summary> /// <param name="waitableResults">An array of work item results</param> /// <param name="waitHandles">An array of wait handles to fill</param> private static void GetWaitHandles( IWaitableResult[] waitableResults, WaitHandle[] waitHandles) { for (int i = 0; i < waitableResults.Length; ++i) { WorkItemResult wir = waitableResults[i].GetWorkItemResult() as WorkItemResult; Debug.Assert(null != wir, "All waitableResults must be WorkItemResult objects"); waitHandles[i] = wir.GetWorkItem().GetWaitHandle(); } }
/// <summary> /// Wait for all work items to complete /// </summary> /// <param name="waitableResults">Array of work item result objects</param> /// <param name="millisecondsTimeout">The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.</param> /// <param name="exitContext"> /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. /// </param> /// <param name="cancelWaitHandle">A cancel wait handle to interrupt the wait if needed</param> /// <returns> /// true when every work item in waitableResults has completed; otherwise false. /// </returns> internal static bool WaitAll( IWaitableResult[] waitableResults, int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle) { if (0 == waitableResults.Length) { return true; } bool success; WaitHandle[] waitHandles = new WaitHandle[waitableResults.Length]; GetWaitHandles(waitableResults, waitHandles); if ((null == cancelWaitHandle) && (waitHandles.Length <= 64)) { success = STPEventWaitHandle.WaitAll(waitHandles, millisecondsTimeout, exitContext); } else { success = true; int millisecondsLeft = millisecondsTimeout; Stopwatch stopwatch = Stopwatch.StartNew(); WaitHandle[] whs; if (null != cancelWaitHandle) { whs = new WaitHandle[] { null, cancelWaitHandle }; } else { whs = new WaitHandle[] { null }; } bool waitInfinitely = (Timeout.Infinite == millisecondsTimeout); // Iterate over the wait handles and wait for each one to complete. // We cannot use WaitHandle.WaitAll directly, because the cancelWaitHandle // won't affect it. // Each iteration we update the time left for the timeout. for (int i = 0; i < waitableResults.Length; ++i) { // WaitAny don't work with negative numbers if (!waitInfinitely && (millisecondsLeft < 0)) { success = false; break; } whs[0] = waitHandles[i]; int result = STPEventWaitHandle.WaitAny(whs, millisecondsLeft, exitContext); if ((result > 0) || (STPEventWaitHandle.WaitTimeout == result)) { success = false; break; } if (!waitInfinitely) { // Update the time left to wait millisecondsLeft = millisecondsTimeout - (int)stopwatch.ElapsedMilliseconds; } } } // Release the wait handles ReleaseWaitHandles(waitableResults); return success; }