public void Nested() { using (var sleepHelper = new SleepHelper()) { var signal = new ManualResetEventSlim(); var listener = new Listener(); var outerDone = false; var innerDone = false; var asyncToken1 = listener.BeginAsyncOperation("Test"); var task = new Task(() => { signal.Set(); sleepHelper.Sleep(TimeSpan.FromMilliseconds(500)); using (listener.BeginAsyncOperation("Test")) { sleepHelper.Sleep(TimeSpan.FromMilliseconds(500)); innerDone = true; } sleepHelper.Sleep(TimeSpan.FromMilliseconds(500)); outerDone = true; }); task.CompletesAsyncOperation(asyncToken1); task.Start(TaskScheduler.Default); Wait(listener, signal); Assert.True(innerDone, "Should have completed the inner task"); Assert.True(outerDone, "Should have completed the outer task"); } }
public void Cancel() { using (var sleepHelper = new SleepHelper()) { var signal = new ManualResetEventSlim(); var listener = new Listener(); var done = false; var continued = false; var asyncToken1 = listener.BeginAsyncOperation("Test"); var task = new Task(() => { signal.Set(); sleepHelper.Sleep(TimeSpan.FromMilliseconds(500)); var asyncToken2 = listener.BeginAsyncOperation("Test"); var queuedTask = new Task(() => { sleepHelper.Sleep(TimeSpan.FromSeconds(5)); continued = true; }); asyncToken2.Dispose(); queuedTask.Start(TaskScheduler.Default); done = true; }); task.CompletesAsyncOperation(asyncToken1); task.Start(TaskScheduler.Default); Wait(listener, signal); Assert.True(done, "Cancelling should have completed the current task."); Assert.False(continued, "Continued Task when it shouldn't have."); } }
public void QueuedOperation() { using (var sleepHelper = new SleepHelper()) { var signal = new ManualResetEventSlim(); var listener = new Listener(); var done = false; var asyncToken1 = listener.BeginAsyncOperation("Test"); var task = new Task(() => { signal.Set(); sleepHelper.Sleep(TimeSpan.FromMilliseconds(500)); var asyncToken2 = listener.BeginAsyncOperation("Test"); var queuedTask = new Task(() => { sleepHelper.Sleep(TimeSpan.FromMilliseconds(500)); done = true; }); queuedTask.CompletesAsyncOperation(asyncToken2); queuedTask.Start(TaskScheduler.Default); }); task.CompletesAsyncOperation(asyncToken1); task.Start(TaskScheduler.Default); Wait(listener, signal); Assert.True(done, "Should have waited for the queued operation to finish!"); } }
public void IgnoredCancel() { using (var sleepHelper = new SleepHelper()) { var signal = new ManualResetEventSlim(); var listener = new Listener(); var done = false; var queuedFinished = false; var cancelledFinished = false; var asyncToken1 = listener.BeginAsyncOperation("Test"); var task = new Task(() => { using (listener.BeginAsyncOperation("Test")) { var cancelledTask = new Task(() => { sleepHelper.Sleep(TimeSpan.FromSeconds(10)); cancelledFinished = true; }); signal.Set(); cancelledTask.Start(TaskScheduler.Default); } sleepHelper.Sleep(TimeSpan.FromMilliseconds(500)); // Now that we've cancelled the first request, queue another one to make sure we wait for it. var asyncToken2 = listener.BeginAsyncOperation("Test"); var queuedTask = new Task(() => { sleepHelper.Sleep(TimeSpan.FromSeconds(1)); queuedFinished = true; }); queuedTask.CompletesAsyncOperation(asyncToken2); queuedTask.Start(TaskScheduler.Default); done = true; }); task.CompletesAsyncOperation(asyncToken1); task.Start(TaskScheduler.Default); Wait(listener, signal); Assert.True(done, "Cancelling should have completed the current task."); Assert.True(queuedFinished, "Continued didn't run, but it was supposed to ignore the cancel."); Assert.False(cancelledFinished, "We waited for the cancelled task to finish."); } }
public void Enqueue(ProjectId projectId, bool needDependencyTracking = false) { UpdateLastAccessTime(); using (_workGate.DisposableWait(CancellationToken)) { // the project is already in the queue. nothing needs to be done if (_pendingWork.ContainsKey(projectId)) { return; } var data = new Data( projectId, needDependencyTracking, Listener.BeginAsyncOperation( nameof(Enqueue), tag: _registration.Workspace ) ); _pendingWork.Add(projectId, data); _gate.Release(); } Logger.Log( FunctionId.WorkCoordinator_Project_Enqueue, s_enqueueLogger, Environment.TickCount, projectId ); }
public void Enqueue(WorkItem item) { Contract.ThrowIfFalse(item.DocumentId != null, "can only enqueue a document work item"); // Don't enqueue item if we don't have any high priority analyzers if (Analyzers.IsEmpty) { return; } // we only put workitem in high priority queue if there is a text change. // this is to prevent things like opening a file, changing in other files keep enqueuing // expensive high priority work. if (!item.InvocationReasons.Contains(PredefinedInvocationReasons.SyntaxChanged)) { return; } if (!_processor._documentTracker.SupportsDocumentTracking && _processor._registration.Workspace.Kind is WorkspaceKind.RemoteWorkspace) { Debug.Fail($"Unexpected use of '{nameof(ExportIncrementalAnalyzerProviderAttribute.HighPriorityForActiveFile)}' in workspace kind '{_processor._registration.Workspace.Kind}' that cannot support active file tracking."); } // check whether given item is for active document, otherwise, nothing to do here if (_processor._documentTracker.TryGetActiveDocument() != item.DocumentId) { return; } // we need to clone due to waiter EnqueueActiveFileItem(item.WithAsyncToken(Listener.BeginAsyncOperation("ActiveFile"))); }
public async Task EnqueueWorkItemAsync(Document document) { // we are shutting down CancellationToken.ThrowIfCancellationRequested(); // call to this method is serialized. and only this method does the writing. var priorityService = document.GetLanguageService <IWorkCoordinatorPriorityService>(); var isLowPriority = priorityService != null && await priorityService .IsLowPriorityAsync(document, CancellationToken) .ConfigureAwait(false); _processor.Enqueue( new WorkItem( document.Id, document.Project.Language, InvocationReasons.SemanticChanged, isLowPriority, activeMember: null, Listener.BeginAsyncOperation( nameof(EnqueueWorkItemAsync), tag: EnqueueItem ) ) ); }
public void Enqueue(WorkItem item) { Contract.ThrowIfFalse(item.DocumentId != null, "can only enqueue a document work item"); // Don't enqueue item if we don't have any high priority analyzers if (this.Analyzers.IsEmpty) { return; } // we only put workitem in high priority queue if there is a text change. // this is to prevent things like opening a file, changing in other files keep enqueuing // expensive high priority work. if (!item.InvocationReasons.Contains(PredefinedInvocationReasons.SyntaxChanged)) { return; } // check whether given item is for active document, otherwise, nothing to do here if (_processor._documentTracker == null || _processor._documentTracker.TryGetActiveDocument() != item.DocumentId) { return; } // we need to clone due to waiter EnqueueActiveFileItem(item.WithAsyncToken(Listener.BeginAsyncOperation("ActiveFile"))); }
private void PushTextChanges(Document oldDocument, Document newDocument) { // this pushes text changes to the remote side if it can. // this is purely perf optimization. whether this pushing text change // worked or not doesn't affect feature's functionality. // // this basically see whether it can cheaply find out text changes // between 2 snapshots, if it can, it will send out that text changes to // remote side. // // the remote side, once got the text change, will again see whether // it can use that text change information without any high cost and // create new snapshot from it. // // otherwise, it will do the normal behavior of getting full text from // VS side. this optimization saves times we need to do full text // synchronization for typing scenario. if ((oldDocument.TryGetText(out var oldText) == false) || (newDocument.TryGetText(out var newText) == false)) { // we only support case where text already exist return; } // get text changes var textChanges = newText.GetTextChanges(oldText); if (textChanges.Count == 0) { // no changes return; } // whole document case if (textChanges.Count == 1 && textChanges[0].Span.Length == oldText.Length) { // no benefit here. pulling from remote host is more efficient return; } // only cancelled when remote host gets shutdown var token = Listener.BeginAsyncOperation(nameof(PushTextChanges)); _textChangeQueue.ScheduleTask(async() => { var client = await _service.Workspace.TryGetRemoteHostClientAsync(CancellationToken).ConfigureAwait(false); if (client == null) { return; } var state = await oldDocument.State.GetStateChecksumsAsync(CancellationToken).ConfigureAwait(false); await client.TryRunRemoteAsync( WellKnownRemoteHostServices.RemoteHostService, nameof(IRemoteHostService.SynchronizeTextAsync), new object[] { oldDocument.Id, state.Text, textChanges }, CancellationToken).ConfigureAwait(false); }, CancellationToken).CompletesAsyncOperation(token); }
public void MultipleEnqueues() { using (var sleepHelper = new SleepHelper()) { var signal = new ManualResetEventSlim(); var listener = new Listener(); var outerDone = false; var firstQueuedDone = false; var secondQueuedDone = false; var asyncToken1 = listener.BeginAsyncOperation("Test"); var task = new Task(() => { signal.Set(); sleepHelper.Sleep(TimeSpan.FromMilliseconds(500)); var asyncToken2 = listener.BeginAsyncOperation("Test"); var firstQueueTask = new Task(() => { sleepHelper.Sleep(TimeSpan.FromMilliseconds(500)); var asyncToken3 = listener.BeginAsyncOperation("Test"); var secondQueueTask = new Task(() => { sleepHelper.Sleep(TimeSpan.FromMilliseconds(500)); secondQueuedDone = true; }); secondQueueTask.CompletesAsyncOperation(asyncToken3); secondQueueTask.Start(TaskScheduler.Default); firstQueuedDone = true; }); firstQueueTask.CompletesAsyncOperation(asyncToken2); firstQueueTask.Start(TaskScheduler.Default); outerDone = true; }); task.CompletesAsyncOperation(asyncToken1); task.Start(TaskScheduler.Default); Wait(listener, signal); Assert.True(outerDone, "The outer task should have finished!"); Assert.True(firstQueuedDone, "The first queued task should have finished"); Assert.True(secondQueuedDone, "The second queued task should have finished"); } }
private void EnqueueChecksumUpdate() { // event will raised sequencially. no concurrency on this handler if (_workQueue.TryPeek(out _)) { return; } _workQueue.Enqueue(Listener.BeginAsyncOperation(nameof(SolutionChecksumUpdater))); }
internal void RaiseDiagnosticsUpdated(DiagnosticsUpdatedArgs args) { // all diagnostics events are serialized. var ev = _eventMap.GetEventHandlers <EventHandler <DiagnosticsUpdatedArgs> >(DiagnosticsUpdatedEventName); if (ev.HasHandlers) { var asyncToken = Listener.BeginAsyncOperation(nameof(RaiseDiagnosticsUpdated)); _eventQueue.ScheduleTask(() => ev.RaiseEvent(handler => handler(this, args))).CompletesAsyncOperation(asyncToken); } }
public void SecondCompletion() { using (var sleepHelper = new SleepHelper()) { var signal1 = new ManualResetEventSlim(); var signal2 = new ManualResetEventSlim(); var listener = new Listener(); var firstDone = false; var secondDone = false; var asyncToken1 = listener.BeginAsyncOperation("Test"); var firstTask = Task.Factory.StartNew(() => { signal1.Set(); sleepHelper.Sleep(TimeSpan.FromMilliseconds(500)); firstDone = true; }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default); firstTask.CompletesAsyncOperation(asyncToken1); firstTask.Wait(); var asyncToken2 = listener.BeginAsyncOperation("Test"); var secondTask = Task.Factory.StartNew(() => { signal2.Set(); sleepHelper.Sleep(TimeSpan.FromMilliseconds(500)); secondDone = true; }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default); secondTask.CompletesAsyncOperation(asyncToken2); // give it two signals since second one might not have started when WaitTask.Wait is called - race condition Wait(listener, signal1, signal2); Assert.True(firstDone, "First didn't finish"); Assert.True(secondDone, "Should have waited for the second task"); } }
private async Task ProcessDocumentAsync(Solution solution, ImmutableArray <IIncrementalAnalyzer> analyzers, WorkItem workItem, CancellationToken cancellationToken) { Contract.ThrowIfNull(workItem.DocumentId); if (CancellationToken.IsCancellationRequested) { return; } var processedEverything = false; var documentId = workItem.DocumentId; try { using (Logger.LogBlock(FunctionId.WorkCoordinator_ProcessDocumentAsync, w => w.ToString(), workItem, cancellationToken)) { var document = solution.GetDocument(documentId); if (document != null) { await _processor.ProcessDocumentAnalyzersAsync(document, analyzers, workItem, cancellationToken).ConfigureAwait(false); } if (!cancellationToken.IsCancellationRequested) { processedEverything = true; } } } catch (Exception e) when(FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { throw ExceptionUtilities.Unreachable; } finally { // we got cancelled in the middle of processing the document. // let's make sure newly enqueued work item has all the flag needed. // Avoid retry attempts after cancellation is requested, since work will not be processed // after that point. if (!processedEverything && !CancellationToken.IsCancellationRequested) { _workItemQueue.AddOrReplace(workItem.Retry(Listener.BeginAsyncOperation("ReenqueueWorkItem"))); } SolutionCrawlerLogger.LogProcessActiveFileDocument(_processor._logAggregator, documentId.Id, processedEverything); // remove one that is finished running _workItemQueue.MarkWorkItemDoneFor(workItem.DocumentId); } }
private void EnqueueChecksumUpdate() { // event will raised sequencially. no concurrency on this handler if (_event.CurrentCount > 0) { return; } lock (_gate) { _lastToken = _lastToken ?? Listener.BeginAsyncOperation(nameof(SolutionChecksumUpdater)); } _event.Release(); }
internal void RaiseBulkDiagnosticsUpdated(Func <Action <DiagnosticsUpdatedArgs>, Task> eventActionAsync) { // all diagnostics events are serialized. var ev = _eventMap.GetEventHandlers <EventHandler <DiagnosticsUpdatedArgs> >(DiagnosticsUpdatedEventName); if (ev.HasHandlers) { // we do this bulk update to reduce number of tasks (with captured data) enqueued. // we saw some "out of memory" due to us having long list of pending tasks in memory. // this is to reduce for such case to happen. Action <DiagnosticsUpdatedArgs> raiseEvents = args => ev.RaiseEvent(handler => handler(this, args)); var asyncToken = Listener.BeginAsyncOperation(nameof(RaiseDiagnosticsUpdated)); _eventQueue.ScheduleTask(() => eventActionAsync(raiseEvents)).CompletesAsyncOperation(asyncToken); } }
public void Enqueue(Document document, SyntaxPath?changedMember) { UpdateLastAccessTime(); using (_workGate.DisposableWait(CancellationToken)) { if (_pendingWork.TryGetValue(document.Id, out var data)) { // create new async token and dispose old one. var newAsyncToken = Listener.BeginAsyncOperation( nameof(Enqueue), tag: _registration.Workspace ); data.AsyncToken.Dispose(); _pendingWork[document.Id] = new Data( document, data.ChangedMember == changedMember ? changedMember : null, newAsyncToken ); return; } _pendingWork.Add( document.Id, new Data( document, changedMember, Listener.BeginAsyncOperation( nameof(Enqueue), tag: _registration.Workspace ) ) ); _gate.Release(); } Logger.Log( FunctionId.WorkCoordinator_SemanticChange_Enqueue, s_enqueueLogger, Environment.TickCount, document.Id, changedMember != null ); }
public void Operation() { using (var sleepHelper = new SleepHelper()) { var signal = new ManualResetEventSlim(); var listener = new Listener(); var done = false; var asyncToken = listener.BeginAsyncOperation("Test"); var task = new Task(() => { signal.Set(); sleepHelper.Sleep(TimeSpan.FromSeconds(1)); done = true; }); task.CompletesAsyncOperation(asyncToken); task.Start(); Wait(listener, signal); Assert.True(done, "The operation should have completed"); } }
public void Operation() { using (var sleepHelper = new SleepHelper()) { var signal = new ManualResetEventSlim(); var listener = new Listener(); var done = false; var asyncToken = listener.BeginAsyncOperation("Test"); var task = new Task(() => { signal.Set(); sleepHelper.Sleep(TimeSpan.FromSeconds(1)); done = true; }); task.CompletesAsyncOperation(asyncToken); task.Start(TaskScheduler.Default); Wait(listener, signal); Assert.True(done, "The operation should have completed"); } }
private async Task ProcessProjectAsync(ImmutableArray <IIncrementalAnalyzer> analyzers, WorkItem workItem, CancellationToken cancellationToken) { if (CancellationToken.IsCancellationRequested) { return; } // we do have work item for this project var projectId = workItem.ProjectId; var processedEverything = false; var processingSolution = Processor._registration.GetSolutionToAnalyze(); try { using (Logger.LogBlock(FunctionId.WorkCoordinator_ProcessProjectAsync, w => w.ToString(), workItem, cancellationToken)) { var project = processingSolution.GetProject(projectId); if (project != null) { var reasons = workItem.InvocationReasons; var semanticsChanged = reasons.Contains(PredefinedInvocationReasons.SemanticChanged) || reasons.Contains(PredefinedInvocationReasons.SolutionRemoved); using (Processor.EnableCaching(project.Id)) { await Processor.RunAnalyzersAsync(analyzers, project, workItem, (a, p, c) => a.AnalyzeProjectAsync(p, semanticsChanged, reasons, c), cancellationToken).ConfigureAwait(false); } } else { SolutionCrawlerLogger.LogProcessProjectNotExist(Processor._logAggregator); await RemoveProjectAsync(projectId, cancellationToken).ConfigureAwait(false); } if (!cancellationToken.IsCancellationRequested) { processedEverything = true; } } } catch (Exception e) when(FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { throw ExceptionUtilities.Unreachable; } finally { // we got cancelled in the middle of processing the project. // let's make sure newly enqueued work item has all the flag needed. // Avoid retry attempts after cancellation is requested, since work will not be processed // after that point. if (!processedEverything && !CancellationToken.IsCancellationRequested) { _workItemQueue.AddOrReplace(workItem.Retry(Listener.BeginAsyncOperation("ReenqueueWorkItem"))); } SolutionCrawlerLogger.LogProcessProject(Processor._logAggregator, projectId.Id, processedEverything); // remove one that is finished running _workItemQueue.MarkWorkItemDoneFor(projectId); } }
private async Task ProcessDocumentAsync(ImmutableArray <IIncrementalAnalyzer> analyzers, WorkItem workItem, CancellationToken cancellationToken) { Contract.ThrowIfNull(workItem.DocumentId); if (CancellationToken.IsCancellationRequested) { return; } var processedEverything = false; var documentId = workItem.DocumentId; // we should always use solution snapshot after workitem is removed from the queue. // otherwise, we can have a race such as below. // // 1.solution crawler picked up a solution // 2.before processing the solution, an workitem got changed // 3.and then the work item got picked up from the queue // 4.and use the work item with the solution that got picked up in step 1 // // step 2 is happening because solution has changed, but step 4 used old solution from step 1 // that doesn't have effects of the solution changes. // // solution crawler must remove the work item from the queue first and then pick up the soluton, // so that the queue gets new work item if there is any solution changes after the work item is removed // from the queue // // using later version of solution is always fine since, as long as there is new work item in the queue, // solution crawler will eventually call the last workitem with the lastest solution // making everything to catch up var solution = Processor.CurrentSolution; try { using (Logger.LogBlock(FunctionId.WorkCoordinator_ProcessDocumentAsync, w => w.ToString(), workItem, cancellationToken)) { var document = solution.GetDocument(documentId); if (document != null) { // if we are called because a document is opened, we invalidate the document so that // it can be re-analyzed. otherwise, since newly opened document has same version as before // analyzer will simply return same data back if (workItem.MustRefresh && !workItem.IsRetry) { var isOpen = document.IsOpen(); await ProcessOpenDocumentIfNeededAsync(analyzers, workItem, document, isOpen, cancellationToken).ConfigureAwait(false); await ProcessCloseDocumentIfNeededAsync(analyzers, workItem, document, isOpen, cancellationToken).ConfigureAwait(false); } // check whether we are having special reanalyze request await ProcessReanalyzeDocumentAsync(workItem, document, cancellationToken).ConfigureAwait(false); await Processor.ProcessDocumentAnalyzersAsync(document, analyzers, workItem, cancellationToken).ConfigureAwait(false); } else { SolutionCrawlerLogger.LogProcessDocumentNotExist(Processor._logAggregator); await RemoveDocumentAsync(documentId, cancellationToken).ConfigureAwait(false); } if (!cancellationToken.IsCancellationRequested) { processedEverything = true; } } } catch (Exception e) when(FatalError.ReportUnlessCanceled(e)) { throw ExceptionUtilities.Unreachable; } finally { // we got cancelled in the middle of processing the document. // let's make sure newly enqueued work item has all the flag needed. // Avoid retry attempts after cancellation is requested, since work will not be processed // after that point. if (!processedEverything && !CancellationToken.IsCancellationRequested) { _workItemQueue.AddOrReplace(workItem.Retry(Listener.BeginAsyncOperation("ReenqueueWorkItem"))); } SolutionCrawlerLogger.LogProcessDocument(Processor._logAggregator, documentId.Id, processedEverything); // remove one that is finished running _workItemQueue.MarkWorkItemDoneFor(workItem.DocumentId); } }
public void QueuedOperation() { using (var sleepHelper = new SleepHelper()) { var signal = new ManualResetEventSlim(); var listener = new Listener(); var done = false; var asyncToken1 = listener.BeginAsyncOperation("Test"); var task = new Task(() => { signal.Set(); sleepHelper.Sleep(TimeSpan.FromMilliseconds(500)); var asyncToken2 = listener.BeginAsyncOperation("Test"); var queuedTask = new Task(() => { sleepHelper.Sleep(TimeSpan.FromMilliseconds(500)); done = true; }); queuedTask.CompletesAsyncOperation(asyncToken2); queuedTask.Start(); }); task.CompletesAsyncOperation(asyncToken1); task.Start(); Wait(listener, signal); Assert.True(done, "Should have waited for the queued operation to finish!"); } }
public void SecondCompletion() { using (var sleepHelper = new SleepHelper()) { var signal1 = new ManualResetEventSlim(); var signal2 = new ManualResetEventSlim(); var listener = new Listener(); var firstDone = false; var secondDone = false; var asyncToken1 = listener.BeginAsyncOperation("Test"); var firstTask = Task.Factory.StartNew(() => { signal1.Set(); sleepHelper.Sleep(TimeSpan.FromMilliseconds(500)); firstDone = true; }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default); firstTask.CompletesAsyncOperation(asyncToken1); firstTask.Wait(); var asyncToken2 = listener.BeginAsyncOperation("Test"); var secondTask = Task.Factory.StartNew(() => { signal2.Set(); sleepHelper.Sleep(TimeSpan.FromMilliseconds(500)); secondDone = true; }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default); secondTask.CompletesAsyncOperation(asyncToken2); // give it two signals since second one might not have started when WaitTask.Wait is called - race condition Wait(listener, signal1, signal2); Assert.True(firstDone, "First didn't finish"); Assert.True(secondDone, "Should have waited for the second task"); } }
public void IgnoredCancel() { using (var sleepHelper = new SleepHelper()) { var signal = new ManualResetEventSlim(); var listener = new Listener(); var done = false; var queuedFinished = false; var cancelledFinished = false; var asyncToken1 = listener.BeginAsyncOperation("Test"); var task = new Task(() => { using (listener.BeginAsyncOperation("Test")) { var cancelledTask = new Task(() => { sleepHelper.Sleep(TimeSpan.FromSeconds(10)); cancelledFinished = true; }); signal.Set(); cancelledTask.Start(); } sleepHelper.Sleep(TimeSpan.FromMilliseconds(500)); // Now that we've cancelled the first request, queue another one to make sure we wait for it. var asyncToken2 = listener.BeginAsyncOperation("Test"); var queuedTask = new Task(() => { sleepHelper.Sleep(TimeSpan.FromSeconds(1)); queuedFinished = true; }); queuedTask.CompletesAsyncOperation(asyncToken2); queuedTask.Start(); done = true; }); task.CompletesAsyncOperation(asyncToken1); task.Start(); Wait(listener, signal); Assert.True(done, "Cancelling should have completed the current task."); Assert.True(queuedFinished, "Continued didn't run, but it was supposed to ignore the cancel."); Assert.False(cancelledFinished, "We waited for the cancelled task to finish."); } }
public void MultipleEnqueues() { using (var sleepHelper = new SleepHelper()) { var signal = new ManualResetEventSlim(); var listener = new Listener(); var outerDone = false; var firstQueuedDone = false; var secondQueuedDone = false; var asyncToken1 = listener.BeginAsyncOperation("Test"); var task = new Task(() => { signal.Set(); sleepHelper.Sleep(TimeSpan.FromMilliseconds(500)); var asyncToken2 = listener.BeginAsyncOperation("Test"); var firstQueueTask = new Task(() => { sleepHelper.Sleep(TimeSpan.FromMilliseconds(500)); var asyncToken3 = listener.BeginAsyncOperation("Test"); var secondQueueTask = new Task(() => { sleepHelper.Sleep(TimeSpan.FromMilliseconds(500)); secondQueuedDone = true; }); secondQueueTask.CompletesAsyncOperation(asyncToken3); secondQueueTask.Start(); firstQueuedDone = true; }); firstQueueTask.CompletesAsyncOperation(asyncToken2); firstQueueTask.Start(); outerDone = true; }); task.CompletesAsyncOperation(asyncToken1); task.Start(); Wait(listener, signal); Assert.True(outerDone, "The outer task should have finished!"); Assert.True(firstQueuedDone, "The first queued task should have finished"); Assert.True(secondQueuedDone, "The second queued task should have finished"); } }
public void Nested() { using (var sleepHelper = new SleepHelper()) { var signal = new ManualResetEventSlim(); var listener = new Listener(); var outerDone = false; var innerDone = false; var asyncToken1 = listener.BeginAsyncOperation("Test"); var task = new Task(() => { signal.Set(); sleepHelper.Sleep(TimeSpan.FromMilliseconds(500)); using (listener.BeginAsyncOperation("Test")) { sleepHelper.Sleep(TimeSpan.FromMilliseconds(500)); innerDone = true; } sleepHelper.Sleep(TimeSpan.FromMilliseconds(500)); outerDone = true; }); task.CompletesAsyncOperation(asyncToken1); task.Start(); Wait(listener, signal); Assert.True(innerDone, "Should have completed the inner task"); Assert.True(outerDone, "Should have completed the outer task"); } }
public void Cancel() { using (var sleepHelper = new SleepHelper()) { var signal = new ManualResetEventSlim(); var listener = new Listener(); var done = false; var continued = false; var asyncToken1 = listener.BeginAsyncOperation("Test"); var task = new Task(() => { signal.Set(); sleepHelper.Sleep(TimeSpan.FromMilliseconds(500)); var asyncToken2 = listener.BeginAsyncOperation("Test"); var queuedTask = new Task(() => { sleepHelper.Sleep(TimeSpan.FromSeconds(5)); continued = true; }); asyncToken2.Dispose(); queuedTask.Start(); done = true; }); task.CompletesAsyncOperation(asyncToken1); task.Start(); Wait(listener, signal); Assert.True(done, "Cancelling should have completed the current task."); Assert.False(continued, "Continued Task when it shouldn't have."); } }
private IAsyncToken BeginOperation(string taskName) => Listener.BeginAsyncOperation(taskName);