mirror of
https://github.com/goatcorp/Dalamud.git
synced 2025-12-14 20:54:16 +01:00
60 lines
2.2 KiB
C#
60 lines
2.2 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace Dalamud.Utility;
|
|
|
|
/// <summary>
|
|
/// A set of utilities around and for better asynchronous behavior.
|
|
/// </summary>
|
|
public static class AsyncUtils
|
|
{
|
|
/// <summary>
|
|
/// Race a set of tasks, returning either the first to succeed or an aggregate of all exceptions. This helper does
|
|
/// not perform any automatic cancellation of losing tasks, nor does it handle exceptions of losing tasks.
|
|
/// </summary>
|
|
/// <remarks>Derived from <a href="https://stackoverflow.com/a/37529395">this StackOverflow post</a>.</remarks>
|
|
/// <param name="tasks">A list of tasks to race.</param>
|
|
/// <typeparam name="T">The return type of all raced tasks.</typeparam>
|
|
/// <exception cref="AggregateException">Thrown when all tasks given to this method fail.</exception>
|
|
/// <returns>Returns the first task that completes, according to <see cref="Task.IsCompletedSuccessfully"/>.</returns>
|
|
public static Task<T> FirstSuccessfulTask<T>(ICollection<Task<T>> tasks)
|
|
{
|
|
var tcs = new TaskCompletionSource<T>();
|
|
var remainingTasks = tasks.Count;
|
|
|
|
foreach (var task in tasks)
|
|
{
|
|
task.ContinueWith(t =>
|
|
{
|
|
if (t.IsCompletedSuccessfully)
|
|
{
|
|
tcs.TrySetResult(t.Result);
|
|
}
|
|
else if (Interlocked.Decrement(ref remainingTasks) == 0)
|
|
{
|
|
tcs.SetException(new AggregateException(tasks.SelectMany(f => f.Exception?.InnerExceptions)));
|
|
}
|
|
});
|
|
}
|
|
|
|
return tcs.Task;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Provide a <see cref="Task.Delay(int, CancellationToken)"/> that won't throw an exception when it's canceled.
|
|
/// </summary>
|
|
/// <inheritdoc cref="Task.Delay(int, CancellationToken)"/>
|
|
public static async Task CancellableDelay(int millisecondsDelay, CancellationToken cancellationToken)
|
|
{
|
|
try
|
|
{
|
|
await Task.Delay(millisecondsDelay, cancellationToken).ConfigureAwait(false);
|
|
}
|
|
catch (TaskCanceledException)
|
|
{
|
|
}
|
|
}
|
|
}
|