/// <summary> /// Gets a task for the completion source which execute continuations for TaskCompletionSource.SetResult asynchronously. /// </summary> public static Task <T> GetAsyncCompletion <T>(this TaskSourceSlim <T> completion) { if (completion.Task.IsCompleted) { return(completion.Task); } return(GetTaskWithAsyncContinuation(completion)); }
private static async Task <T> GetTaskWithAsyncContinuation <T>(this TaskSourceSlim <T> completion) { var result = await completion.Task; // Yield to not block the thread which sets the result of the completion await Task.Yield(); return(result); }
public static Task <T> FromException <T>(Exception ex) { Contract.RequiresNotNull(ex); var failureSource = TaskSourceSlim.Create <T>(); failureSource.SetException(ex); return(failureSource.Task); }
public static Task <T> FromException <T>(Exception ex) { Contract.Requires(ex != null); Contract.Ensures(Contract.Result <Task <T> >() != null); var failureSource = TaskSourceSlim.Create <T>(); failureSource.SetException(ex); return(failureSource.Task); }
/// <summary> /// Gets <see cref="CancellationTokenAwaitable"/> from a given <paramref name="token"/> that can be used in async methods to await the cancellation. /// </summary> /// <remarks> /// The method returns a special disposable type instead of just returning a Task. /// This is important, because the client code need to "unregister" the callback from the token when some other operations are done and the cancellation is no longer relevant. /// Just returning a task on a token that is never trigerred will effectively cause a memory leak. /// Here is a previous implementation of this method: /// <code>public static async Task ToAwaitable(this CancellationToken token) { try {await Task.Delay(Timeout.Infinite, token);} catch(TaskCanceledException) {} }</code> /// The `Delay` impelmentaiton checks if the timeout is infinite and won't start the timer, but it still will create a `DelayPromise` instance /// and will register for the cancellation. /// It means that if we call such a method many times with the same cancellation token, the registration list will grow indefinitely causing potential performance issues. /// </remarks> public static CancellationTokenAwaitable ToAwaitable(this CancellationToken token) { if (!token.CanBeCanceled) { // If the token can not be canceled, return a special global instance with a task that will never be finished. return(CancellationTokenAwaitable.NonCancellableAwaitable); } var tcs = TaskSourceSlim.Create <object>(); var registration = token.Register(static tcs => ((TaskSourceSlim <object>)tcs).SetResult(null), tcs);
/// <summary> /// Creates a TPL Task that is marked as completed when any <see cref="WaitHandle"/> in the array is signaled. /// </summary> /// <param name="handles">The handles whose signals triggers the task to be completed. Do not use a <see cref="Mutex"/> here.</param> /// <param name="timeout">The timeout (in milliseconds) after which the task will return a value of WaitTimeout.</param> /// <returns>A Task that is completed after any handle is signaled.</returns> /// <remarks> /// There is a (brief) time delay between when the handles are signaled and when the task is marked as completed. /// </remarks> public static Task <int> ToTask(this WaitHandle[] handles, int timeout = Timeout.Infinite) { Contract.Requires(handles != null); Contract.RequiresForAll(handles, handle => handles != null); var tcs = TaskSourceSlim.Create <int>(); int signalledHandle = WaitHandle.WaitAny(handles, 0); if (signalledHandle != WaitHandle.WaitTimeout) { // An optimization for if the handle is already signaled // to return a completed task. tcs.SetResult(signalledHandle); } else { var localVariableInitLock = new object(); lock (localVariableInitLock) { RegisteredWaitHandle[] callbackHandles = new RegisteredWaitHandle[handles.Length]; for (int i = 0; i < handles.Length; i++) { callbackHandles[i] = ThreadPool.RegisterWaitForSingleObject( handles[i], (state, timedOut) => { int handleIndex = (int)state; if (timedOut) { tcs.TrySetResult(WaitHandle.WaitTimeout); } else { tcs.TrySetResult(handleIndex); } // We take a lock here to make sure the outer method has completed setting the local variable callbackHandles contents. lock (localVariableInitLock) { foreach (var handle in callbackHandles) { handle.Unregister(null); } } }, state: i, millisecondsTimeOutInterval: timeout, executeOnlyOnce: true); } } } return(tcs.Task); }
static BoolTask() { TrueCompletion = TaskSourceSlim.Create <bool>(); TrueCompletion.SetResult(true); True = TrueCompletion.Task; TrueCompletionSource = new TaskCompletionSource <bool>(); TrueCompletionSource.SetResult(true); FalseCompletion = TaskSourceSlim.Create <bool>(); FalseCompletion.SetResult(false); False = FalseCompletion.Task; FalseCompletionSource = new TaskCompletionSource <bool>(false); FalseCompletionSource.SetResult(false); }