Example #1
0
        private void StartAsynchronousComputation(AsynchronousComputationToStart computationToStart, Request requestToCompleteSynchronously)
        {
            var cancellationToken = computationToStart.CancellationTokenSource.Token;

            try
            {
                cancellationToken.ThrowIfCancellationRequested();

                // DO NOT ACCESS ANY FIELDS OR STATE BEYOND THIS POINT. Since this function
                // runs unsynchronized, it's possible that during this function this request
                // might be cancelled, and then a whole additional request might start and
                // complete inline, and cache the result. By grabbing state before we check
                // the cancellation token, we can be assured that we are only operating on
                // a state that was complete.
                try
                {
                    // We avoid creating a full closure just to pass the token along
                    // Also, use TaskContinuationOptions.ExecuteSynchronously so that we inline
                    // the continuation if asynchronousComputeFunction completes synchronously
                    var task = computationToStart.AsynchronousComputeFunction(cancellationToken);

                    task.ContinueWith(
                        (t, s) => CompleteWithTask(t, ((CancellationTokenSource)s).Token),
                        computationToStart.CancellationTokenSource,
                        cancellationToken,
                        TaskContinuationOptions.ExecuteSynchronously,
                        TaskScheduler.Default);

                    if (requestToCompleteSynchronously != null && task.IsCompleted)
                    {
                        using (TakeLock(CancellationToken.None))
                        {
                            task = GetCachedValueAndCacheThisValueIfNoneCached_NoLock(task);
                        }

                        requestToCompleteSynchronously.CompleteFromTaskSynchronously(task);
                    }
                }
                catch (Exception e) if (ExceptionHelpers.CrashUnlessCanceled(e))
                    {
                        throw ExceptionUtilities.Unreachable;
                    }
            }
            catch (OperationCanceledException oce) if (CrashIfCanceledWithDifferentToken(oce, cancellationToken))
                {
                    // As long as it's the right token, this means that our thread was the first thread
                    // to start an asynchronous computation, but the requestor cancelled as we were starting up
                    // the computation.
                    throw ExceptionUtilities.Unreachable;
                }
        }
        public static Task SafeStartNew(
            this TaskFactory factory,
            Action action,
            CancellationToken cancellationToken,
            TaskCreationOptions creationOptions,
            TaskScheduler scheduler)
        {
            Action wrapped = () =>
            {
                try
                {
                    action();
                }
                catch (Exception e) if (ExceptionHelpers.CrashUnlessCanceled(e))
                    {
                        throw ExceptionUtilities.Unreachable;
                    }
            };

            // The one and only place we can call StartNew().
            return(factory.StartNew(wrapped, cancellationToken, creationOptions, scheduler));
        }
Example #3
0
        public static Task <TResult> SafeStartNew <TResult>(
            this TaskFactory factory,
            Func <TResult> func,
            CancellationToken cancellationToken,
            TaskCreationOptions creationOptions,
            TaskScheduler scheduler)
        {
            Func <TResult> wrapped = () =>
            {
                try
                {
                    return(func());
                }
                catch (Exception e) if (ExceptionHelpers.CrashUnlessCanceled(e))
                    {
                        throw ExceptionUtilities.Unreachable;
                    }
            };

            // The one and only place we can call StartNew<>().
            return(factory.StartNew(wrapped, cancellationToken, creationOptions, scheduler));
        }