/// <summary> /// Execute an action on the thread pool after a specified number of milliseconds. /// </summary> /// <param name="action">The action to be executed.</param> /// <param name="delay">The amount of time to wait before execution, in milliseconds.</param> /// <returns>A cancellation token that can be used to cancel the operation.</returns> public static ICancellationToken DelayAndExecute(this Action action, int delay) { object waitHandleLock = new object(); ManualResetEvent waitObj = new ManualResetEvent(false); DelayCancellationToken cancellationToken = new DelayCancellationToken(waitObj); RegisteredWaitHandle waitHandle = null; WaitOrTimerCallback callback = (state, timeout) => { if (Interlocked.Exchange(ref waitHandleLock, null) == null) { waitHandle.Unregister(null); cancellationToken.Dispose(); } if (!timeout) { return; } action(); }; waitHandle = ThreadPool.RegisterWaitForSingleObject(waitObj, callback, null, delay, true); if (Interlocked.Exchange(ref waitHandleLock, null) == null) { waitHandle.Unregister(null); cancellationToken.Dispose(); } return(cancellationToken); }
/// <summary> /// Execute an action on the thread pool after a specified number of milliseconds. /// </summary> /// <param name="action">The action to be executed.</param> /// <param name="delay">The amount of time to wait before execution, in milliseconds.</param> /// <returns>A cancellation token that can be used to cancel the operation.</returns> public static ICancellationToken DelayAndExecute(this Action action, int delay) { object waitHandleLock = new object(); ManualResetEvent waitObj = new ManualResetEvent(false); DelayCancellationToken cancellationToken = new DelayCancellationToken(waitObj); RegisteredWaitHandle waitHandle = null; void callback(object state, bool timeout) { // Even if the callback timed out, another thread may cancel // the cancellation token before we are able to dispose of it // so we explicitly cancel the token in order to be sure #if !MONO timeout = timeout && cancellationToken.Cancel(); #else timeout = !waitObj.WaitOne(0) && cancellationToken.Cancel(); #endif // Both the callback thread and the caller thread will // attempt to set the wait handle lock to null, and the // last one to do so has to unregister and dispose if (Interlocked.Exchange(ref waitHandleLock, null) == null) { waitHandle.Unregister(null); cancellationToken.Dispose(); } // If we didn't time out, then the action // was canceled by another thread if (!timeout) { return; } action(); } waitHandle = ThreadPool.RegisterWaitForSingleObject(waitObj, callback, null, delay, true); // Both the callback thread and the caller thread will // attempt to set the wait handle lock to null, and the // last one to do so has to unregister and dispose if (Interlocked.Exchange(ref waitHandleLock, null) == null) { waitHandle.Unregister(null); cancellationToken.Dispose(); } return(cancellationToken); }
/// <summary> /// Execute an action on the thread pool after a specified number of milliseconds. /// </summary> /// <param name="action">The action to be executed.</param> /// <param name="delay">The amount of time to wait before execution, in milliseconds.</param> /// <returns>A cancellation token that can be used to cancel the operation.</returns> public static ICancellationToken DelayAndExecute(this Action action, int delay) { object waitHandleLock = new object(); ManualResetEvent waitObj = new ManualResetEvent(false); DelayCancellationToken cancellationToken = new DelayCancellationToken(waitObj); RegisteredWaitHandle waitHandle = null; WaitOrTimerCallback callback = (state, timeout) => { // Even if the callback timed out, another thread may cancel // the cancellation token before we are able to dispose of it // so we explicitly cancel the token in order to be sure timeout = timeout && cancellationToken.Cancel(); // Both the callback thread and the caller thread will // attempt to set the wait handle lock to null, and the // last one to to do so has to unregister and dispose if (Interlocked.Exchange(ref waitHandleLock, null) == null) { waitHandle.Unregister(null); cancellationToken.Dispose(); } // If we didn't time out, then the action // was cancelled by another thread if (!timeout) return; action(); }; waitHandle = ThreadPool.RegisterWaitForSingleObject(waitObj, callback, null, delay, true); // Both the callback thread and the caller thread will // attempt to set the wait handle lock to null, and the // last one to to do so has to unregister and dispose if (Interlocked.Exchange(ref waitHandleLock, null) == null) { waitHandle.Unregister(null); cancellationToken.Dispose(); } return cancellationToken; }