예제 #1
0
        public void CancellationDuringInlinedComputationFromGetValueWithoutSynchronousComputationStillCachesResult()
        {
            using (new StopTheThreadPoolContext())
            {
                int computations = 0;
                var requestCancellationTokenSource = new CancellationTokenSource();

                var lazy = new AsyncLazy <object>(c =>
                {
                    Interlocked.Increment(ref computations);

                    // We do not want to ever use the cancellation token that we are passed to this
                    // computation. Rather, we will ignore it but cancel any request that is
                    // outstanding.
                    requestCancellationTokenSource.Cancel();

                    return(Task.FromResult(new object()));
                }, cacheResult: true);

                // Do a first request. Even though we will get a cancellation during the evaluation,
                // since we handed a result back, that result must be cached.
                var firstRequestResult = lazy.GetValue(requestCancellationTokenSource.Token);

                // And a second request. We'll let this one complete normally.
                var secondRequestResult = lazy.GetValue(CancellationToken.None);

                // We should have gotten the same cached result, and we should have only computed once.
                Assert.Same(secondRequestResult, firstRequestResult);
                Assert.Equal(1, computations);
            }
        }
예제 #2
0
        public void SynchronousRequestShouldCacheValueWithAsynchronousComputeFunction()
        {
            var lazy = new AsyncLazy <object>(c => Task.FromResult(new object()), cacheResult: true);

            var firstRequestResult  = lazy.GetValue(CancellationToken.None);
            var secondRequestResult = lazy.GetValue(CancellationToken.None);

            Assert.Same(secondRequestResult, firstRequestResult);
        }
예제 #3
0
        public void SynchronousRequestShouldCacheValueWithSynchronousComputeFunction()
        {
            var lazy = new AsyncLazy <object>(c => { throw new Exception("The asynchronous compute function should never be called."); }, c => new object(), cacheResult: true);

            var firstRequestResult  = lazy.GetValue(CancellationToken.None);
            var secondRequestResult = lazy.GetValue(CancellationToken.None);

            Assert.Same(secondRequestResult, firstRequestResult);
        }
예제 #4
0
        public void SynchronousRequestShouldCacheValueWithAsynchronousComputeFunction()
        {
            var lazy = new AsyncLazy<object>(c => Task.FromResult(new object()), cacheResult: true);

            var firstRequestResult = lazy.GetValue(CancellationToken.None);
            var secondRequestResult = lazy.GetValue(CancellationToken.None);

            Assert.Same(secondRequestResult, firstRequestResult);
        }
예제 #5
0
        public void GetValue_Precanceled(bool specifyJtf)
        {
            var jtf  = specifyJtf ? new JoinableTaskContext().Factory : null; // use our own so we don't get main thread deadlocks, which isn't the point of this test.
            var lazy = new AsyncLazy <GenericParameterHelper>(() => Task.FromResult(new GenericParameterHelper(5)), jtf);

            Assert.Throws <OperationCanceledException>(() => lazy.GetValue(new CancellationToken(canceled: true)));
        }
예제 #6
0
        public void GetValue(bool specifyJtf)
        {
            var jtf  = specifyJtf ? new JoinableTaskContext().Factory : null; // use our own so we don't get main thread deadlocks, which isn't the point of this test.
            var lazy = new AsyncLazy <GenericParameterHelper>(() => Task.FromResult(new GenericParameterHelper(5)), jtf);

            Assert.Equal(5, lazy.GetValue().Data);
        }
예제 #7
0
        public async Task GetValue_CalledAfterGetValueAsyncHasCompleted(bool specifyJtf)
        {
            var jtf    = specifyJtf ? new JoinableTaskContext().Factory : null; // use our own so we don't get main thread deadlocks, which isn't the point of this test.
            var lazy   = new AsyncLazy <GenericParameterHelper>(() => Task.FromResult(new GenericParameterHelper(5)), jtf);
            var result = await lazy.GetValueAsync();

            Assert.Same(result, lazy.GetValue());
        }
예제 #8
0
        public async Task GetValue_ThenCanceled(bool specifyJtf)
        {
            var completeValueFactory = new AsyncManualResetEvent();
            var jtf  = specifyJtf ? new JoinableTaskContext().Factory : null; // use our own so we don't get main thread deadlocks, which isn't the point of this test.
            var lazy = new AsyncLazy <GenericParameterHelper>(
                async delegate
            {
                await completeValueFactory;
                return(new GenericParameterHelper(5));
            },
                jtf);
            var cts = new CancellationTokenSource();
            Task <GenericParameterHelper> getValueTask = Task.Run(() => lazy.GetValue(cts.Token));

            Assert.False(getValueTask.IsCompleted);
            cts.Cancel();
            await Assert.ThrowsAnyAsync <OperationCanceledException>(() => getValueTask);
        }
예제 #9
0
        public async Task GetValue_CalledAfterGetValueAsync_InProgress(bool specifyJtf)
        {
            var completeValueFactory = new AsyncManualResetEvent();
            var jtf  = specifyJtf ? new JoinableTaskContext().Factory : null; // use our own so we don't get main thread deadlocks, which isn't the point of this test.
            var lazy = new AsyncLazy <GenericParameterHelper>(
                async delegate
            {
                await completeValueFactory;
                return(new GenericParameterHelper(5));
            },
                jtf);
            Task <GenericParameterHelper> getValueAsyncTask = lazy.GetValueAsync();
            Task <GenericParameterHelper> getValueTask      = Task.Run(() => lazy.GetValue());

            Assert.False(getValueAsyncTask.IsCompleted);
            Assert.False(getValueTask.IsCompleted);
            completeValueFactory.Set();
            GenericParameterHelper[] results = await Task.WhenAll(getValueAsyncTask, getValueTask);

            Assert.Same(results[0], results[1]);
        }
 protected virtual void Dispose(bool disposing)
 {
     if (!_disposedValue)
     {
         if (disposing)
         {
             if (_serviceBrokerClient.IsValueCreated)
             {
                 _serviceBrokerClient.GetValue().Dispose();
             }
             try
             {
                 CloseChannelAsync().GetAwaiter().GetResult();
             }
             catch
             {
                 // Ignore exceptions
             }
         }
         _disposedValue = true;
     }
 }
예제 #11
0
        public void ValueFactoryRequiresMainThreadHeldByOtherInGetValue()
        {
            var ctxt = SingleThreadedTestSynchronizationContext.New();

            SynchronizationContext.SetSynchronizationContext(ctxt);
            var context        = new JoinableTaskContext();
            var asyncPump      = context.Factory;
            var originalThread = Thread.CurrentThread;

            var evt  = new AsyncManualResetEvent();
            var lazy = new AsyncLazy <object>(
                async delegate
            {
                // It is important that no await appear before this JTF.Run call, since
                // we're testing that the value factory is not invoked while the AsyncLazy
                // holds a private lock that would deadlock when called from another thread.
                asyncPump.Run(async delegate
                {
                    await asyncPump.SwitchToMainThreadAsync(this.TimeoutToken);
                });
                await Task.Yield();
                return(new object());
            },
                asyncPump);

            var backgroundRequest = Task.Run(async delegate
            {
                return(await lazy.GetValueAsync());
            });

            Thread.Sleep(AsyncDelay); // Give the background thread time to call GetValueAsync(), but it doesn't yield (when the test was written).
            var foregroundValue = lazy.GetValue(this.TimeoutToken);
            var backgroundValue = asyncPump.Run(() => backgroundRequest);

            Assert.Same(foregroundValue, backgroundValue);
        }
예제 #12
0
        private void SynchronousContinuationsDoNotRunWithinGetValueCallCore(TaskStatus expectedTaskStatus)
        {
            var synchronousComputationStartedEvent = new ManualResetEvent(initialState: false);
            var synchronousComputationShouldCompleteEvent = new ManualResetEvent(initialState: false);

            var requestCancellationTokenSource = new CancellationTokenSource();

            // First, create an async lazy that will only ever do synchronous computations.
            var lazy = new AsyncLazy<int>(
                asynchronousComputeFunction: c => { throw new Exception("We should not get an asynchronous computation."); },
                synchronousComputeFunction: c =>
                {
                    // Notify that the synchronous computation started
                    synchronousComputationStartedEvent.Set();

                    // And now wait when we should finish
                    synchronousComputationShouldCompleteEvent.WaitOne();

                    c.ThrowIfCancellationRequested();

                    if (expectedTaskStatus == TaskStatus.Faulted)
                    {
                        // We want to see what happens if this underlying task faults, so let's fault!
                        throw new Exception("Task blew up!");
                    }

                    return 42;
                },
                cacheResult: false);

            // Second, start a synchronous request. While we are in the GetValue, we will record which thread is being occupied by the request
            Thread synchronousRequestThread = null;
            Task.Factory.StartNew(() =>
            {
                try
                {
                    synchronousRequestThread = Thread.CurrentThread;
                    lazy.GetValue(requestCancellationTokenSource.Token);
                }
                finally // we do test GetValue in exceptional scenarios, so we should deal with this
                {
                    synchronousRequestThread = null;
                }
            }, CancellationToken.None);

            // Wait until this request has actually started
            synchronousComputationStartedEvent.WaitOne();

            // Good, we now have a synchronous request running. An async request should simply create a task that would
            // be completed when the synchronous request completes. We want to assert that if we were to run a continuation
            // from this task that's marked ExecuteSynchronously, we do not run it inline atop the synchronous request.
            bool? asyncContinuationRanSynchronously = null;
            TaskStatus? observedAntecedentTaskStatus = null;

            var asyncContinuation = lazy.GetValueAsync(requestCancellationTokenSource.Token).ContinueWith(antecedent =>
                {
                    var currentSynchronousRequestThread = synchronousRequestThread;

                    asyncContinuationRanSynchronously = currentSynchronousRequestThread != null && currentSynchronousRequestThread == Thread.CurrentThread;
                    observedAntecedentTaskStatus = antecedent.Status;
                },
                CancellationToken.None,
                TaskContinuationOptions.ExecuteSynchronously,
                TaskScheduler.Default);

            // Excellent, the async continuation is scheduled. Let's complete the underlying computation.
            if (expectedTaskStatus == TaskStatus.Canceled)
            {
                requestCancellationTokenSource.Cancel();
            }

            synchronousComputationShouldCompleteEvent.Set();

            // And wait for our continuation to run
            asyncContinuation.Wait();

            Assert.False(asyncContinuationRanSynchronously.Value, "The continuation did not run asynchronously.");
            Assert.Equal(expectedTaskStatus, observedAntecedentTaskStatus.Value);
        }
예제 #13
0
        public void SynchronousRequestShouldCacheValueWithSynchronousComputeFunction()
        {
            var lazy = new AsyncLazy<object>(c => { throw new Exception("The asynchronous compute function should never be called."); }, c => new object(), cacheResult: true);

            var firstRequestResult = lazy.GetValue(CancellationToken.None);
            var secondRequestResult = lazy.GetValue(CancellationToken.None);

            Assert.Same(secondRequestResult, firstRequestResult);
        }
예제 #14
0
        public void CancellationDuringInlinedComputationFromGetValueWithoutSynchronousComputationStillCachesResult()
        {
            using (new StopTheThreadPoolContext())
            {
                int computations = 0;
                var requestCancellationTokenSource = new CancellationTokenSource();

                var lazy = new AsyncLazy<object>(c =>
                {
                    Interlocked.Increment(ref computations);

                    // We do not want to ever use the cancellation token that we are passed to this
                    // computation. Rather, we will ignore it but cancel any request that is
                    // outstanding.
                    requestCancellationTokenSource.Cancel();

                    return Task.FromResult(new object());
                }, cacheResult: true);

                // Do a first request. Even though we will get a cancellation during the evaluation,
                // since we handed a result back, that result must be cached.
                var firstRequestResult = lazy.GetValue(requestCancellationTokenSource.Token);

                // And a second request. We'll let this one complete normally.
                var secondRequestResult = lazy.GetValue(CancellationToken.None);

                // We should have gotten the same cached result, and we should have only computed once.
                Assert.Same(secondRequestResult, firstRequestResult);
                Assert.Equal(1, computations);
            }
        }
예제 #15
0
        private static void SynchronousContinuationsDoNotRunWithinGetValueCallCore(TaskStatus expectedTaskStatus)
        {
            var synchronousComputationStartedEvent        = new ManualResetEvent(initialState: false);
            var synchronousComputationShouldCompleteEvent = new ManualResetEvent(initialState: false);

            var requestCancellationTokenSource = new CancellationTokenSource();

            // First, create an async lazy that will only ever do synchronous computations.
            var lazy = new AsyncLazy <int>(
                asynchronousComputeFunction: c => { throw new Exception("We should not get an asynchronous computation."); },
                synchronousComputeFunction: c =>
            {
                // Notify that the synchronous computation started
                synchronousComputationStartedEvent.Set();

                // And now wait when we should finish
                synchronousComputationShouldCompleteEvent.WaitOne();

                c.ThrowIfCancellationRequested();

                if (expectedTaskStatus == TaskStatus.Faulted)
                {
                    // We want to see what happens if this underlying task faults, so let's fault!
                    throw new Exception("Task blew up!");
                }

                return(42);
            },
                cacheResult: false);

            // Second, start a synchronous request. While we are in the GetValue, we will record which thread is being occupied by the request
            Thread synchronousRequestThread = null;

            Task.Factory.StartNew(() =>
            {
                try
                {
                    synchronousRequestThread = Thread.CurrentThread;
                    lazy.GetValue(requestCancellationTokenSource.Token);
                }
                finally // we do test GetValue in exceptional scenarios, so we should deal with this
                {
                    synchronousRequestThread = null;
                }
            }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Current);

            // Wait until this request has actually started
            synchronousComputationStartedEvent.WaitOne();

            // Good, we now have a synchronous request running. An async request should simply create a task that would
            // be completed when the synchronous request completes. We want to assert that if we were to run a continuation
            // from this task that's marked ExecuteSynchronously, we do not run it inline atop the synchronous request.
            bool?      asyncContinuationRanSynchronously = null;
            TaskStatus?observedAntecedentTaskStatus      = null;

            var asyncContinuation = lazy.GetValueAsync(requestCancellationTokenSource.Token).ContinueWith(antecedent =>
            {
                var currentSynchronousRequestThread = synchronousRequestThread;

                asyncContinuationRanSynchronously = currentSynchronousRequestThread != null && currentSynchronousRequestThread == Thread.CurrentThread;
                observedAntecedentTaskStatus      = antecedent.Status;
            },
                                                                                                          CancellationToken.None,
                                                                                                          TaskContinuationOptions.ExecuteSynchronously,
                                                                                                          TaskScheduler.Default);

            // Excellent, the async continuation is scheduled. Let's complete the underlying computation.
            if (expectedTaskStatus == TaskStatus.Canceled)
            {
                requestCancellationTokenSource.Cancel();
            }

            synchronousComputationShouldCompleteEvent.Set();

            // And wait for our continuation to run
            asyncContinuation.Wait();

            Assert.False(asyncContinuationRanSynchronously.Value, "The continuation did not run asynchronously.");
            Assert.Equal(expectedTaskStatus, observedAntecedentTaskStatus.Value);
        }
예제 #16
0
 internal SyntaxTreeBase GetSyntaxTreeSynchronously(CancellationToken cancellationToken)
 {
     return(_lazySyntaxTree.GetValue(cancellationToken));
 }
예제 #17
0
 public void EnsureSubscription()
 {
     // make sure we have file notification subscribed
     _ = _fileChangeCookie.GetValue(CancellationToken.None);
 }