Skip to content

Commit 5b04bb2

Browse files
author
Lifeng Lu
committed
prevent a race condition during disposing.
1 parent 262d9e9 commit 5b04bb2

File tree

1 file changed

+25
-13
lines changed

1 file changed

+25
-13
lines changed

src/Microsoft.VisualStudio.ProjectSystem.Managed/ProjectSystem/Debug/LaunchSettingsProvider.cs

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,17 @@ protected override void Initialize()
220220
JoinUpstreamDataSources(_projectSubscriptionService.ProjectRuleSource, _commonProjectServices.Project.Capabilities);
221221
}
222222

223+
FileChangeScheduler?.Dispose();
224+
225+
Assumes.Present(_projectServices.ProjectAsynchronousTasks);
226+
227+
// Create our scheduler for processing file changes
228+
FileChangeScheduler = new TaskDelayScheduler(
229+
FileChangeProcessingDelay,
230+
_commonProjectServices.ThreadingService,
231+
_projectServices.ProjectAsynchronousTasks.UnloadCancellationToken);
232+
233+
223234
// establish the file watcher. We don't need wait this, because files can be changed in the system anyway, so blocking our process
224235
// doesn't provide real benefit. It is of course possible that the file is changed before the watcher is established. To eliminate this
225236
// gap, we can recheck file after the watcher is established. I will skip this for now.
@@ -525,16 +536,23 @@ protected async Task HandleLaunchSettingsFileChangedAsync()
525536
{
526537
Assumes.NotNull(FileChangeScheduler);
527538

528-
await FileChangeScheduler.ScheduleAsyncTask(token =>
539+
try
529540
{
530-
if (token.IsCancellationRequested)
541+
await FileChangeScheduler.ScheduleAsyncTask(token =>
531542
{
532-
return Task.CompletedTask;
533-
}
543+
if (token.IsCancellationRequested)
544+
{
545+
return Task.CompletedTask;
546+
}
534547

535-
// Updates need to be sequenced
536-
return _sequentialTaskQueue.ExecuteTask(() => UpdateProfilesAsync(null));
537-
});
548+
// Updates need to be sequenced
549+
return _sequentialTaskQueue.ExecuteTask(() => UpdateProfilesAsync(null));
550+
});
551+
}
552+
catch (ObjectDisposedException)
553+
{
554+
// during closing the FileChangeScheduler can be disposed while the task to process the last file change is still running.
555+
}
538556
}
539557
}
540558

@@ -557,15 +575,9 @@ protected async Task EnsureSettingsFolderAsync()
557575
/// </summary>
558576
private async Task<IFileWatcher?> WatchLaunchSettingsFileAsync()
559577
{
560-
FileChangeScheduler?.Dispose();
561-
562578
Assumes.Present(_projectServices.ProjectAsynchronousTasks);
563-
564579
CancellationToken cancellationToken = _projectServices.ProjectAsynchronousTasks.UnloadCancellationToken;
565580

566-
// Create our scheduler for processing file changes
567-
FileChangeScheduler = new TaskDelayScheduler(FileChangeProcessingDelay, _commonProjectServices.ThreadingService, cancellationToken);
568-
569581
IFileWatcher? fileWatcher = null;
570582

571583
string launchSettingsToWatch = await GetLaunchSettingsFilePathAsync();

0 commit comments

Comments
 (0)