En nuestro proyecto, hemos decidido proporcionar un mecanismo de cancelación para los usuarios con la ayuda de CancellationToken .
Debido a la estructura de los trabajos en el proyecto, necesito un mecanismo de cancelación jerárquico. Por jerárquico, me refiero a que la cancelación de la fuente principal hace que todas las fuentes secundarias se cancelen recursivamente, pero las cancelaciones de las fuentes secundarias no se propagan a la principal.
¿Existe tal opción disponible en .NET lista para usar? De lo contrario, no estoy seguro de si registrar un delegado en el token principal es suficiente o si se deben dar más consideraciones.
Sí, esta funcionalidad existe lista para usar. Consulte el método CancellationTokenSource.CreateLinkedTokenSource .
Crea un
CancellationTokenSourceque estará en estado cancelado cuando alguno de los tokens de origen esté en estado cancelado.
Ejemplo:
using var parentCts = new CancellationTokenSource(); using var childrenCts = CancellationTokenSource .CreateLinkedTokenSource(parentCts.Token); parentCts.Cancel(); // Cancel the children too childrenCts.Cancel(); // Doesn't affect the parentSegún la implementación en el código fuente de Linked2CancellationTokenSource , llegué a esta implementación:
public class HierarchicalCancellationTokenSource : CancellationTokenSource { private readonly CancellationTokenRegistration _parentReg; public HierarchicalCancellationTokenSource(CancellationToken parentToken) { this._parentReg = parentToken.Register( static s => ((CancellationTokenSource)s).Cancel(false), this, useSynchronizationContext: false); } protected override void Dispose(bool disposing) { if (disposing) { this._parentReg.Dispose(); } base.Dispose(disposing); } }Y una demostración:
CancellationTokenSource[] CreateChildSources(CancellationTokenSource parentSource) => Enumerable.Range(0, 2) .Select(_ => new HierarchicalCancellationTokenSource(parentSource.Token)) .ToArray(); var rootSource = new CancellationTokenSource(); var childSources = CreateChildSources(rootSource); var grandChildSources = childSources.SelectMany(CreateChildSources).ToArray(); var allTokens = new[] { rootSource.Token } .Concat(childSources.Select(s => s.Token)) .Concat(grandChildSources.Select(s => s.Token)) .ToArray(); for (int i = 0; i < allTokens.Length; i++) { allTokens[i].Register( i => Console.WriteLine( $"{new string('+', (int)Math.Log2((int)i))}{i} canceled."), i + 1); } rootSource.Cancel(); /* Output: 1 canceled. +3 canceled. ++7 canceled. ++6 canceled. +2 canceled. ++5 canceled. ++4 canceled. */