// Copyright Epic Games, Inc. All Rights Reserved. using System; using System.Threading; using System.Threading.Tasks; namespace EpicGames.Core { /// /// Runs a task in the background and allows stopping it on demand /// public sealed class BackgroundTask : IDisposable, IAsyncDisposable { readonly Func _runTask; Task _task = Task.CompletedTask; readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource(); /// /// Accessor for the inner task /// public Task Task => _task; /// /// Constructor. Note that the task does not start until is called. /// /// public BackgroundTask(Func runTask) { _runTask = runTask; } /// public void Dispose() { if (!_task.IsCompleted) { _cancellationTokenSource.Cancel(); StopAsync().Wait(); } _cancellationTokenSource.Dispose(); } /// public async ValueTask DisposeAsync() { await StopAsync(); _cancellationTokenSource.Dispose(); } /// /// Creates and starts a new background task instance /// /// /// public static BackgroundTask StartNew(Func runTask) { BackgroundTask task = new BackgroundTask(runTask); task.Start(); return task; } /// /// Starts the task /// public void Start() { if (!_task.IsCompleted) { throw new InvalidOperationException("Background task is already running"); } _task = Task.Run(() => _runTask(_cancellationTokenSource.Token), _cancellationTokenSource.Token); } /// /// Signals the cancellation token and waits for the task to finish /// /// public async Task StopAsync() { if (!_task.IsCompleted) { try { _cancellationTokenSource.Cancel(); await _task; } catch (OperationCanceledException) { } } } } }