/// <summary>
        /// Execute a continuation task when a task completes. The continuation
        /// task is synchronously created by a continuation function, and then unwrapped to
        /// form the result of this method. The <paramref name="supportsErrors"/>
        /// parameter specifies whether the continuation is executed if the antecedent task is faulted.
        /// </summary>
        /// <remarks>
        /// <para>If the antecedent <paramref name="task"/> is cancelled, or faulted with <paramref name="supportsErrors"/>
        /// set to <see langword="false"/>, the status
        /// of the antecedent is directly applied to the task returned by this method; it is
        /// not wrapped in an additional <see cref="AggregateException"/>.
        /// </para>
        ///
        /// <note type="caller">
        /// Since the <paramref name="continuationFunction"/> is executed synchronously, this
        /// method should only be used for lightweight continuation functions. This restriction
        /// applies only to <paramref name="continuationFunction"/> itself, not to the
        /// <see cref="Task"/> returned by it.
        /// </note>
        /// </remarks>
        /// <typeparam name="TSource">The type of the result produced by the antecedent <see cref="Task{TResult}"/>.</typeparam>
        /// <param name="task">The antecedent task.</param>
        /// <param name="continuationFunction">The continuation function to execute when <paramref name="task"/> completes. The continuation function returns a <see cref="Task"/> which provides the final result of the continuation.</param>
        /// <param name="supportsErrors"><see langword="true"/> if the <paramref name="continuationFunction"/> properly handles a faulted antecedent task; otherwise, <see langword="false"/>.</param>
        /// <returns>A <see cref="Task"/> representing the unwrapped asynchronous operation.</returns>
        /// <exception cref="ArgumentNullException">
        /// If <paramref name="task"/> is <see langword="null"/>.
        /// <para>-or-</para>
        /// <para>If <paramref name="continuationFunction"/> is <see langword="null"/>.</para>
        /// </exception>
        public static Task Then <TSource>(this Task <TSource> task, Func <Task <TSource>, Task> continuationFunction, bool supportsErrors)
        {
            if (task == null)
            {
                throw new ArgumentNullException("task");
            }
            if (continuationFunction == null)
            {
                throw new ArgumentNullException("continuationFunction");
            }

            TaskCompletionSource <VoidResult> completionSource = new TaskCompletionSource <VoidResult>();

            TaskContinuationOptions successContinuationOptions = supportsErrors ? TaskContinuationOptions.NotOnCanceled : TaskContinuationOptions.OnlyOnRanToCompletion;

            task
            .ContinueWith(continuationFunction, TaskContinuationOptions.ExecuteSynchronously | successContinuationOptions)
            .Unwrap()
            .ContinueWith(
                t =>
            {
                if (task.Status == TaskStatus.RanToCompletion || supportsErrors && task.Status == TaskStatus.Faulted)
                {
                    completionSource.SetFromTask(t);
                }
            }, TaskContinuationOptions.ExecuteSynchronously);

            TaskContinuationOptions failedContinuationOptions = supportsErrors ? TaskContinuationOptions.OnlyOnCanceled : TaskContinuationOptions.NotOnRanToCompletion;

            task
            .ContinueWith(t => completionSource.SetFromTask(t), TaskContinuationOptions.ExecuteSynchronously | failedContinuationOptions);

            return(completionSource.Task);
        }
        /// <summary>
        /// Aa extension method suggesting a possible (but far from real implementation)
        /// of the "Unwrap" extension method.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="task"></param>
        /// <returns></returns>
        public static Task <T> Unwrap2 <T>(this Task <Task <T> > task)
        {
            TaskCompletionSource <T> tcs = new TaskCompletionSource <T>();

            task.ContinueWith((ant) => {
                switch (ant.Status)
                {
                case TaskStatus.Canceled:
                    tcs.TrySetCanceled();
                    break;

                case TaskStatus.Faulted:
                    tcs.TrySetException(ant.Exception.InnerExceptions);
                    break;

                case TaskStatus.RanToCompletion:
                    Task <T> tr = ant.Result;
                    tr.ContinueWith((ant2) => {
                        tcs.SetFromTask(ant2);
                    });
                    break;
                }
            });
            return(tcs.Task);
        }
Beispiel #3
0
		/// <summary>
		/// Switches the GUI into "waiting" mode, then calls <paramref name="taskCreation"/> to create
		/// the task.
		/// If another task is started before the previous task finishes running, the previous task is cancelled.
		/// </summary>
		public Task<T> RunWithCancellation<T>(Func<CancellationToken, Task<T>> taskCreation)
		{
			if (waitAdorner.Visibility != Visibility.Visible) {
				waitAdorner.Visibility = Visibility.Visible;
				// Work around a WPF bug by setting IsIndeterminate only while the progress bar is visible.
				// https://github.com/icsharpcode/ILSpy/issues/593
				progressBar.IsIndeterminate = true;
				waitAdorner.BeginAnimation(OpacityProperty, new DoubleAnimation(0, 1, new Duration(TimeSpan.FromSeconds(0.5)), FillBehavior.Stop));
				var taskBar = MainWindow.Instance.TaskbarItemInfo;
				if (taskBar != null) {
					taskBar.ProgressState = System.Windows.Shell.TaskbarItemProgressState.Indeterminate;
				}
			}
			CancellationTokenSource previousCancellationTokenSource = currentCancellationTokenSource;
			var myCancellationTokenSource = new CancellationTokenSource();
			currentCancellationTokenSource = myCancellationTokenSource;
			// cancel the previous only after current was set to the new one (avoid that the old one still finishes successfully)
			if (previousCancellationTokenSource != null)
				previousCancellationTokenSource.Cancel();
			
			var tcs = new TaskCompletionSource<T>();
			Task<T> task;
			try {
				task = taskCreation(myCancellationTokenSource.Token);
			} catch (OperationCanceledException) {
				task = TaskHelper.FromCancellation<T>();
			} catch (Exception ex) {
				task = TaskHelper.FromException<T>(ex);
			}
			Action continuation = delegate {
				try {
					if (currentCancellationTokenSource == myCancellationTokenSource) {
						currentCancellationTokenSource = null;
						waitAdorner.Visibility = Visibility.Collapsed;
						progressBar.IsIndeterminate = false;
						var taskBar = MainWindow.Instance.TaskbarItemInfo;
						if (taskBar != null) {
							taskBar.ProgressState = System.Windows.Shell.TaskbarItemProgressState.None;
						}
						if (task.IsCanceled) {
							AvalonEditTextOutput output = new AvalonEditTextOutput();
							output.WriteLine("The operation was canceled.");
							ShowOutput(output);
						}
						tcs.SetFromTask(task);
					} else {
						tcs.SetCanceled();
					}
				} finally {
					myCancellationTokenSource.Dispose();
				}
			};
			task.ContinueWith(delegate { Dispatcher.BeginInvoke(DispatcherPriority.Normal, continuation); });
			return tcs.Task;
		}
Beispiel #4
0
        static IEnumerable <Task> _getResponseAsync(TaskCompletionSource <WebResponse> tcs, WebRequest request, TimeSpan timeout)
        {
            using (var cancellation_token = new Concurrency.TimeoutToken(timeout))
                using (var registration_token = cancellation_token.Token.Register(() => { request.Abort(); }))
                {
                    using (var task_get_response = request.GetResponseAsync())
                    {
                        yield return(task_get_response);

                        tcs.SetFromTask(task_get_response);
                        yield break;
                    }
                }
        }
Beispiel #5
0
        public static Task ConvertAsync(string sourceFileName,
                                        string destinationFileName,
                                        CancellationToken cancellationToken)
        {
            // Wire a graph together.
            var source = File.OpenRead(sourceFileName);
            var decoder = CodecFactory.CreateDecoder(sourceFileName);
            var encoder = CodecFactory.CreateEncoder(destinationFileName);
            var destination = File.Create(destinationFileName);

            const int bufferSize = 16384;

            decoder.ErrorDataReceived += (sender, e) => { Console.WriteLine("{0}: {1}", sourceFileName, e.Data); };
            var decoderTask = decoder.Start(cancellationToken);

            // Note that the process has to be started before you can get the stream,
            // otherwise you get InvalidOperationException containing "StandardIn has not been redirected.".
            var sourceToDecoderTask =
                source.CopyToAsync(decoder.InputStream, bufferSize, cancellationToken)
                      .ContinueWith(t => decoder.InputStream.Close());

            encoder.ErrorDataReceived += (sender, e) => { Console.WriteLine("{0}: {1}", destinationFileName, e.Data); };
            var encoderTask = encoder.Start(cancellationToken);

            var decoderToEncoderTask =
                decoder.OutputStream
                       .CopyToAsync(encoder.InputStream, bufferSize, cancellationToken)
                       .ContinueWith(t => encoder.InputStream.Close());

            var encoderToDestination =
                encoder.OutputStream
                       .CopyToAsync(destination, bufferSize, cancellationToken)
                       .ContinueWith(t => destination.Close());

            // We need to propagate the cancelation/exception; use a TCS.
            var completion = new TaskCompletionSource<bool>();
            Task.WhenAll(sourceToDecoderTask, decoderTask, decoderToEncoderTask, encoderTask, encoderToDestination)
                .ContinueWith(t =>
                    {
                        if (t.IsCanceled || t.IsFaulted)
                        {
                            Console.WriteLine("Deleting '{0}'.", destinationFileName);
                            File.Delete(destinationFileName);
                        }

                        completion.SetFromTask(t);
                    });

            return completion.Task;
        }
Beispiel #6
0
        /// <summary>
        /// <paramref name="task"/>가 완료되면, <paramref name="callback"/>을 호출하도록 예약된 새로운 Task를 생성하여,
        /// <paramref name="task"/>의 수행 결과를 설정한 후 제공합니다.
        /// </summary>
        /// <param name="task">실제 수행할 작업</param>
        /// <param name="callback">작업 후 호출할 callback 함수</param>
        /// <param name="state">callback 함수 호출 시 인자값</param>
        /// <returns>작업 완료와 callback 호출까지 모두를 포함한 작업</returns>
        public static Task <TResult> ToAsync <TResult>(this Task <TResult> task, AsyncCallback callback = null, object state = null)
        {
            task.ShouldNotBeNull("task");

            var tcs = new TaskCompletionSource <TResult>(state);

            task.ContinueWith(_ => {
                tcs.SetFromTask(task);
                if (callback != null)
                {
                    callback(tcs.Task);
                }
            });
            return(tcs.Task);
        }
Beispiel #7
0
        public static Task <TResult> ToAsync <TResult>(this Task <TResult> task, AsyncCallback callback, object state)
        {
            if (task == null)
            {
                throw new ArgumentNullException("task");
            }
            var tcs = new TaskCompletionSource <TResult>(state);

            task.ContinueWith(delegate
            {
                tcs.SetFromTask(task);
                callback?.Invoke(tcs.Task);
            });
            return(tcs.Task);
        }
Beispiel #8
0
        /// <summary>
        /// <paramref name="millisecondsDelayed"/> 이후에 <paramref name="function"/>을 수행하는 작업을 생성합니다.
        /// </summary>
        /// <typeparam name="TResult">작업 결과 수형</typeparam>
        /// <param name="factory">Task Factory</param>
        /// <param name="millisecondsDelayed">실행 전에 지연할 시간(밀리초)</param>
        /// <param name="function">실행할 함수</param>
        /// <param name="state">함수 인자 값</param>
        /// <param name="cancellationToken">작업 취소용 토큰</param>
        /// <param name="creationOptions">작업 생성 옵션</param>
        /// <param name="scheduler">작업 스케쥴러</param>
        /// <returns>일정 시간 이후에 함수를 실행하는 작업</returns>
        public static Task <TResult> StartNewDelayed <TResult>(this TaskFactory <TResult> factory,
                                                               int millisecondsDelayed,
                                                               Func <object, TResult> function,
                                                               object state = null,
                                                               CancellationToken?cancellationToken = null,
                                                               TaskCreationOptions?creationOptions = null,
                                                               TaskScheduler scheduler             = null)
        {
            factory.ShouldNotBeNull("factory");
            millisecondsDelayed.ShouldBePositiveOrZero("millisecondsDelayed");
            function.ShouldNotBeNull("function");

            scheduler = scheduler ?? factory.GetTargetScheduler();

            if (IsDebugEnabled)
            {
                log.Debug("일정 시간 이후에 지정한 함수를 수행하는 작업을 생성합니다. 작업지연 시간=[{0}] msecs", millisecondsDelayed);
            }

            var   tcs   = new TaskCompletionSource <TResult>(state);
            Timer timer = null;

            // 주어진 함수를 수행할 Task를 정의
            var functionTask = new Task <TResult>(function, state, creationOptions ?? factory.CreationOptions);

            functionTask.ContinueWith(antecedent => {
                // tcs의 작업 결과를 antecedent.Result로 설정합니다.
                tcs.SetFromTask(antecedent);
                if (timer != null)
                {
                    timer.Dispose();
                }
            },
                                      cancellationToken ?? factory.CancellationToken,
                                      ContinuationOptionsFromCreationOptions(creationOptions ?? factory.CreationOptions) |
                                      TaskContinuationOptions.ExecuteSynchronously,
                                      scheduler);

            // 이렇게 타이머의 Time Callback 함수에서, 사용자 작업을 수행하도록 한다.
            timer = new Timer(task => ((Task)task).Start(scheduler),
                              functionTask,
                              millisecondsDelayed,
                              Timeout.Infinite);

            return(tcs.Task);
        }
        public static Task ToAsync(this Task task, AsyncCallback callback, object state)
        {
            if (task == null)
            {
                throw new ArgumentNullException("task");
            }
            TaskCompletionSource <object> tcs = new TaskCompletionSource <object>(state);

            task.ContinueWith(delegate(Task _)
            {
                tcs.SetFromTask(task);
                if (callback != null)
                {
                    callback(tcs.Task);
                }
            });
            return(tcs.Task);
        }
Beispiel #10
0
        /// <summary>
        /// Creates a Task that represents the completion of another Task, and
        /// that schedules an AsyncCallback to run upon completion.
        /// </summary>
        /// <param name="task">The antecedent Task.</param>
        /// <param name="callback">The AsyncCallback to run.</param>
        /// <param name="state">The object state to use with the AsyncCallback.</param>
        /// <returns>The new task.</returns>
        public static Task <TResult> ToAsync <TResult>(this Task <TResult> task, AsyncCallback callback, object state)
        {
            if (task == null)
            {
                throw new ArgumentNullException(nameof(task));
            }
            TaskCompletionSource <TResult> tcs = new TaskCompletionSource <TResult>(state);

            task.ContinueWith(_ =>
            {
                tcs.SetFromTask(task);
                if (callback == null)
                {
                    return;
                }
                callback(tcs.Task);
            });
            return(tcs.Task);
        }
Beispiel #11
0
        /// <summary>
        /// Creates a Task that represents the completion of another Task, and
        /// that schedules an AsyncCallback to run upon completion.
        /// </summary>
        /// <param name="task">The antecedent Task.</param>
        /// <param name="callback">The AsyncCallback to run.</param>
        /// <param name="state">The object state to use with the AsyncCallback.</param>
        /// <returns>The new task.</returns>
        public static Task ToAsync(this Task task, AsyncCallback callback, object state)
        {
            if (task == null)
            {
                throw new ArgumentNullException(nameof(task));
            }
            TaskCompletionSource <object> tcs = new TaskCompletionSource <object>(state);

            task.ContinueWith((Action <Task>)(_ =>
            {
                tcs.SetFromTask <object>(task);
                if (callback == null)
                {
                    return;
                }
                callback((IAsyncResult)tcs.Task);
            }));
            return((Task)tcs.Task);
        }
Beispiel #12
0
        /// <summary>Creates and schedules a task for execution after the specified time delay.</summary>
        /// <param name="factory">The factory to use to create the task.</param>
        /// <param name="millisecondsDelay">The delay after which the task will be scheduled.</param>
        /// <param name="function">The delegate executed by the task.</param>
        /// <param name="state">An object provided to the delegate.</param>
        /// <param name="cancellationToken">The CancellationToken to assign to the Task.</param>
        /// <param name="creationOptions">Options that control the task's behavior.</param>
        /// <param name="scheduler">The scheduler to which the Task will be scheduled.</param>
        /// <returns>The created Task.</returns>
        public static Task <TResult> StartNewDelayed <TResult>(
            this TaskFactory <TResult> factory,
            int millisecondsDelay, Func <object, TResult> function, object state,
            CancellationToken cancellationToken, TaskCreationOptions creationOptions, TaskScheduler scheduler)
        {
            if (factory == null)
            {
                throw new ArgumentNullException("factory");
            }
            if (millisecondsDelay < 0)
            {
                throw new ArgumentOutOfRangeException("millisecondsDelay");
            }
            if (function == null)
            {
                throw new ArgumentNullException("action");
            }
            if (scheduler == null)
            {
                throw new ArgumentNullException("scheduler");
            }

            // Create the task that will be returned
            var   result = new TaskCompletionSource <TResult>(state);
            Timer timer  = null;

            // Create the task that will run the user's function
            var functionTask = new Task <TResult>(function, state, creationOptions);

            // When the function task completes, transfer the results to the returned task
            functionTask.ContinueWith(t =>
            {
                result.SetFromTask(t);
                timer.Dispose();
            }, cancellationToken, ContinuationOptionsFromCreationOptions(creationOptions) | TaskContinuationOptions.ExecuteSynchronously, scheduler);

            // Start the timer for the trigger
            timer = new Timer(obj => ((Task)obj).Start(scheduler),
                              functionTask, millisecondsDelay, Timeout.Infinite);

            return(result.Task);
        }
Beispiel #13
0
        /// <summary>
        /// <paramref name="task"/>가 완료되면, <paramref name="callback"/>을 호출하도록 예약된 새로운 Task를 생성하여,
        /// <paramref name="task"/>의 수행 결과를 설정한 후 제공합니다.
        /// </summary>
        /// <param name="task">실제 수행할 작업</param>
        /// <param name="callback">작업 후 호출할 callback 함수</param>
        /// <param name="state">callback 함수 호출 시 인자값</param>
        /// <returns>작업 완료와 callback 호출까지 모두를 포함한 작업</returns>
        public static Task ToAsync(this Task task, AsyncCallback callback = null, object state = null)
        {
            task.ShouldNotBeNull("task");

            if (IsDebugEnabled)
            {
                log.Debug("지정된 Task가 완료되면, callback을 호출하도록 하는 새로운 Task를 빌드합니다.");
            }

            var tcs = new TaskCompletionSource <object>(state);

            task.ContinueWith(_ => {
                tcs.SetFromTask(task);
                if (callback != null)
                {
                    callback(tcs.Task);
                }
            },
                              TaskContinuationOptions.ExecuteSynchronously);
            return(tcs.Task);
        }
Beispiel #14
0
        /// <summary>
        /// Creates an <see cref="IAsyncResult"/> object that's suitable to be returned from an APM-style method.
        /// </summary>
        /// <typeparam name="T">The type of value being returned by the EndXxx APM method.</typeparam>
        /// <param name="task">The task that produces the value to be returned.</param>
        /// <param name="callback">The <see cref="AsyncCallback"/> supplied to the BeginXxx APM method.</param>
        /// <param name="state">The state object supplied to the BeginXxx APM method.</param>
        /// <returns>An <see cref="IAsyncResult"/> object that can be returned from an APM-style BeginXxx method.</returns>
        public static IAsyncResult CreateAsyncResult <T>(this Task <T> task, AsyncCallback callback, object state)
        {
            if (task == null)
            {
                throw new ArgumentNullException("task");
            }

            // create result object that can hold the asynchronously-computed value
            TaskCompletionSource <T> result = new TaskCompletionSource <T>(state);

            // set the result (or failure) when the value is known
            task.ContinueWith(t =>
            {
                result.SetFromTask(t);
                if (callback != null)
                {
                    callback(result.Task);
                }
            });

            // the result's task functions as the IAsyncResult APM return value
            return(result.Task);
        }
        /// <summary>
        /// A variant of the previous method but now returning a Task without result
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="U"></typeparam>
        /// <param name="t"></param>
        /// <param name="cont"></param>
        /// <returns></returns>
        public static Task AndThen <T>(this Task <T> t, Func <T, Task> cont)
        {
            TaskCompletionSource <object> tcs = new TaskCompletionSource <object>();

            t.ContinueWith((ant) => {
                switch (ant.Status)
                {
                case TaskStatus.Canceled:
                    tcs.TrySetCanceled();
                    break;

                case TaskStatus.Faulted:
                    tcs.SetException(ant.Exception);
                    break;

                case TaskStatus.RanToCompletion:
                    cont(ant.Result).ContinueWith((ant2) => {
                        tcs.SetFromTask(ant2);
                    }, TaskContinuationOptions.ExecuteSynchronously);
                    break;
                }
            }, TaskContinuationOptions.ExecuteSynchronously);
            return(tcs.Task);
        }
Beispiel #16
0
        /// <summary>
        /// Get all pages in a paginated collection.
        /// </summary>
        /// <remarks>
        /// If <paramref name="progress"/> is non-<see langword="null"/>, the first call to
        /// <see cref="IProgress{T}.Report"/> will specify the <paramref name="page"/>
        /// argument. After each task to obtain to the next page of results completes,
        /// the <see cref="IProgress{T}.Report"/> method will be called again with the
        /// new page of results.
        /// <para>
        /// This method determines that the end of the collection is reached when either of
        /// the following conditions is true.
        /// </para>
        /// <list type="bullet">
        /// <item>The <see cref="ReadOnlyCollectionPage{T}.CanHaveNextPage"/> property returns <see langword="false"/>.</item>
        /// <item>An empty page is reached.</item>
        /// </list>
        /// </remarks>
        /// <typeparam name="T">The type of elements in the collection.</typeparam>
        /// <param name="page">The first page in the collection.</param>
        /// <param name="cancellationToken">The <see cref="CancellationToken"/> that the task will observe.</param>
        /// <param name="progress">An optional callback object to receive progress notifications. If this is <see langword="null"/>, no progress notifications are sent.</param>
        /// <returns>
        /// A <see cref="Task"/> object representing the asynchronous operation. When the operation
        /// completes successfully, the <see cref="Task{TResult}.Result"/> property will contain a
        /// read-only collection containing the complete set of results from the paginated collection.
        /// </returns>
        /// <exception cref="ArgumentNullException">If <paramref name="page"/> is <see langword="null"/>.</exception>
        public static Task <ReadOnlyCollection <T> > GetAllPagesAsync <T>(this ReadOnlyCollectionPage <T> page, CancellationToken cancellationToken, IProgress <ReadOnlyCollectionPage <T> > progress)
        {
            if (page == null)
            {
                throw new ArgumentNullException("page");
            }

            if (progress != null)
            {
                progress.Report(page);
            }

            if (!page.CanHaveNextPage || page.Count == 0)
            {
                return(InternalTaskExtensions.CompletedTask <ReadOnlyCollection <T> >(page));
            }

            TaskCompletionSource <ReadOnlyCollection <T> > taskCompletionSource = new TaskCompletionSource <ReadOnlyCollection <T> >();

            List <T> result = new List <T>(page);
            ReadOnlyCollectionPage <T> currentPage = page;
            Func <Task <ReadOnlyCollectionPage <T> > >   getNextPage  = () => currentPage.GetNextPageAsync(cancellationToken);
            Task <ReadOnlyCollectionPage <T> >           currentTask  = getNextPage();
            Action <Task <ReadOnlyCollectionPage <T> > > continuation = null;

            continuation =
                previousTask =>
            {
                if (previousTask.Status != TaskStatus.RanToCompletion)
                {
                    taskCompletionSource.SetFromTask(previousTask);
                    return;
                }

                currentPage = previousTask.Result;
                if (currentPage == null)
                {
                    // TODO: should we throw an exception instead?
                    taskCompletionSource.SetResult(result.AsReadOnly());
                    return;
                }

                if (progress != null)
                {
                    progress.Report(currentPage);
                }

                result.AddRange(currentPage);
                if (!currentPage.CanHaveNextPage || currentPage.Count == 0)
                {
                    taskCompletionSource.SetResult(result.AsReadOnly());
                    return;
                }

                // continue with the next page
                currentTask = getNextPage();
                // use ContinueWith since the continuation handles cancellation and faulted antecedent tasks
                currentTask.ContinueWith(continuation, TaskContinuationOptions.ExecuteSynchronously);
            };
            // use ContinueWith since the continuation handles cancellation and faulted antecedent tasks
            currentTask.ContinueWith(continuation, TaskContinuationOptions.ExecuteSynchronously);


            return(taskCompletionSource.Task);
        }
Beispiel #17
0
        public static Task EncodeAsync(string sourceFileName,
                                       string destinationFileName,
                                       CancellationToken cancellationToken)
        {
            // Wire a graph together.
            var source = File.OpenRead(sourceFileName);
            var encoder = CodecFactory.CreateEncoder(destinationFileName);
            var destination = File.Create(destinationFileName);

            const int bufferSize = 16384;

            encoder.ErrorDataReceived += (sender, e) => { Console.WriteLine("{0}: {1}", destinationFileName, e.Data); };
            var encoderTask = encoder.Start(cancellationToken);

            var sourceToEncoderTask =
                source.CopyToAsync(encoder.InputStream, bufferSize, cancellationToken)
                      .ContinueWith(t => encoder.InputStream.Close());

            var encoderToDestination =
                encoder.OutputStream
                       .CopyToAsync(destination, bufferSize, cancellationToken)
                       .ContinueWith(t => destination.Close());

            // We need to propagate the cancelation/exception; use a TCS.
            var completion = new TaskCompletionSource<bool>();
            Task.WhenAll(sourceToEncoderTask, encoderTask, encoderToDestination)
                .ContinueWith(t =>
                {
                    if (t.IsCanceled || t.IsFaulted)
                    {
                        Console.WriteLine("Deleting '{0}'.", destinationFileName);
                        File.Delete(destinationFileName);
                    }

                    completion.SetFromTask(t);
                });

            return completion.Task;
        }
 public static void SetFromTask <TResult>(this TaskCompletionSource <TResult> resultSetter, Task <TResult> task)
 {
     resultSetter.SetFromTask(task);
 }
        /// <summary>
        /// Creates a task that will complete after a time delay.
        /// </summary>
        /// <remarks>
        /// If the cancellation token is signaled before the specified time delay, then the task
        /// is completed in <see cref="TaskStatus.Canceled"/> state. Otherwise, the task is
        /// completed in <see cref="TaskStatus.RanToCompletion"/> state once the specified time
        /// delay has expired.
        /// <para>This method ignores any fractional milliseconds when evaluating <paramref name="delay"/>.</para>
        /// </remarks>
        /// <param name="delay">The time span to wait before completing the returned task</param>
        /// <param name="cancellationToken">The cancellation token that will be checked prior to completing the returned task</param>
        /// <returns>A task that represents the time delay</returns>
        /// <exception cref="ArgumentOutOfRangeException">If <paramref name="delay"/> represents a negative time interval.</exception>
        /// <exception cref="TaskCanceledException">If the task has been canceled.</exception>
        /// <exception cref="ObjectDisposedException">If the provided <paramref name="cancellationToken"/> has already been disposed.</exception>
        public static Task Delay(TimeSpan delay, CancellationToken cancellationToken)
        {
#if NET45PLUS
            return(Task.Delay(delay, cancellationToken));
#else
            long totalMilliseconds = (long)delay.TotalMilliseconds;
            if (totalMilliseconds < 0)
            {
                throw new ArgumentOutOfRangeException("delay");
            }

            if (cancellationToken.IsCancellationRequested)
            {
                return(CompletedTask.Canceled());
            }

            if (totalMilliseconds == 0)
            {
                return(CompletedTask.Default);
            }

            TaskCompletionSource <VoidResult> result = new TaskCompletionSource <VoidResult>();

#if !PORTABLE
            TaskCompletionSource <VoidResult> intermediateResult = new TaskCompletionSource <VoidResult>();

            RegisteredWaitHandle timerRegisteredWaitHandle        = null;
            RegisteredWaitHandle cancellationRegisteredWaitHandle = null;

            WaitOrTimerCallback timedOutCallback =
                (object state, bool timedOut) =>
            {
                if (timedOut)
                {
                    intermediateResult.TrySetResult(default(VoidResult));
                }
            };

            IAsyncResult asyncResult = intermediateResult.Task;
            timerRegisteredWaitHandle = ThreadPool.RegisterWaitForSingleObject(asyncResult.AsyncWaitHandle, timedOutCallback, null, delay, true);

            if (cancellationToken.CanBeCanceled)
            {
                WaitOrTimerCallback cancelledCallback =
                    (object state, bool timedOut) =>
                {
                    if (cancellationToken.IsCancellationRequested)
                    {
                        intermediateResult.TrySetCanceled();
                    }
                };

                cancellationRegisteredWaitHandle = ThreadPool.RegisterWaitForSingleObject(cancellationToken.WaitHandle, cancelledCallback, null, Timeout.Infinite, true);
            }

            intermediateResult.Task
            .ContinueWith(
                _ =>
            {
                if (cancellationRegisteredWaitHandle != null)
                {
                    cancellationRegisteredWaitHandle.Unregister(null);
                }

                if (timerRegisteredWaitHandle != null)
                {
                    timerRegisteredWaitHandle.Unregister(null);
                }
            }, TaskContinuationOptions.ExecuteSynchronously)
            .ContinueWith(
                cleanupTask =>
            {
                switch (cleanupTask.Status)
                {
                case TaskStatus.RanToCompletion:
                    result.SetFromTask(intermediateResult.Task);
                    break;

                case TaskStatus.Canceled:
                    result.SetCanceled();
                    break;

                case TaskStatus.Faulted:
                    result.SetException(cleanupTask.Exception.InnerExceptions);
                    break;

                default:
                    throw new InvalidOperationException("Unreachable");
                }
            });
#else
            // Since portable-net40 doesn't provide Task.Delay and also doesn't provide ThreadPool.RegisterWaitForSingleObject,
            // we need to implement this functionality using timers stored in a ConditionalWeakTable, which are associated with
            // the actual Task instance that gets returned by this method.

            CancellationTokenRegistration cancellationTokenRegistration = default(CancellationTokenRegistration);
            Timer timer = null;

            TimerCallback timerCallback =
                state =>
            {
                result.TrySetResult(default(VoidResult));
                timer.Dispose();
                cancellationTokenRegistration.Dispose();
            };

            timer = new Timer(timerCallback, null, Timeout.Infinite, Timeout.Infinite);
            _delayTimers.Add(result.Task, timer);
            timer.Change(delay, TimeSpan.FromMilliseconds(-1));


            if (cancellationToken.CanBeCanceled)
            {
                Action cancellationCallback =
                    () =>
                {
                    result.TrySetCanceled();

                    if (timer != null)
                    {
                        timer.Dispose();
                    }

                    cancellationTokenRegistration.Dispose();
                };

                cancellationTokenRegistration = cancellationToken.Register(cancellationCallback);
            }
#endif

            return(result.Task);
#endif
        }
 static IEnumerable<Task> _getResponseAsync(TaskCompletionSource<WebResponse> tcs, WebRequest request, TimeSpan timeout)
 {
     using (var cancellation_token = new Concurrency.TimeoutToken(timeout))
     using (var registration_token = cancellation_token.Token.Register(() => { request.Abort(); }))
     {
         using (var task_get_response = request.GetResponseAsync())
         {
             yield return task_get_response;
             tcs.SetFromTask(task_get_response);
             yield break;
         }
     }
 }