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); } }
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); }
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); }
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); }
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))); }
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); }
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()); }
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); }
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; } }
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); }
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); }
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); }
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); } }
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); }
internal SyntaxTreeBase GetSyntaxTreeSynchronously(CancellationToken cancellationToken) { return(_lazySyntaxTree.GetValue(cancellationToken)); }
public void EnsureSubscription() { // make sure we have file notification subscribed _ = _fileChangeCookie.GetValue(CancellationToken.None); }