Created
September 14, 2023 12:30
-
-
Save StephenCleary/d1b122265f404f27e04e2d933a324618 to your computer and use it in GitHub Desktop.
Resettable CTSs using InterlockedState
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Threading; | |
/// <summary> | |
/// A <see cref="CancellationTokenSource"/> that resets itself to uncanceled after <see cref="Cancel"/> is called. | |
/// </summary> | |
public sealed class AutoResetCancellationTokenSource | |
{ | |
/// <summary> | |
/// Cancels any tokens previously returned from <see cref="Token"/>, and resets this instance to an uncancelled state. | |
/// </summary> | |
public void Cancel() | |
{ | |
var (oldState, _) = InterlockedState.Transform(ref _cts, state => null); | |
oldState?.Cancel(); | |
} | |
/// <summary> | |
/// Returns the current <see cref="CancellationToken"/>. | |
/// </summary> | |
public CancellationToken Token | |
{ | |
get | |
{ | |
var (_, newState) = InterlockedState.Transform(ref _cts, state => state switch | |
{ | |
null => new CancellationTokenSource(), | |
not null => state, | |
}); | |
return newState!.Token; | |
} | |
} | |
/// <summary> | |
/// Either <c>null</c> or a <see cref="CancellationTokenSource"/> instance that is not canceled. | |
/// </summary> | |
private CancellationTokenSource? _cts; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Threading; | |
/// <summary> | |
/// A <see cref="CancellationTokenSource"/> that stays canceled until <see cref="Reset"/> is called. | |
/// </summary> | |
public sealed class ManualResetCancellationTokenSource | |
{ | |
/// <inheritdoc cref="CancellationTokenSource.IsCancellationRequested"/> | |
public bool IsCancellationRequested | |
{ | |
get | |
{ | |
var state = InterlockedState.Read(ref _cts); | |
if (state == null) | |
return false; | |
return state.IsCancellationRequested; | |
} | |
} | |
/// <summary> | |
/// Returns the current <see cref="CancellationToken"/>. | |
/// </summary> | |
public CancellationToken Token | |
{ | |
get | |
{ | |
var (_, newState) = InterlockedState.Transform(ref _cts, state => state switch | |
{ | |
null => new CancellationTokenSource(), | |
not null => state, | |
}); | |
return newState!.Token; | |
} | |
} | |
/// <summary> | |
/// Cancels any tokens previously returned from <see cref="Token"/>. | |
/// </summary> | |
public void Cancel() | |
{ | |
var (_, newState) = InterlockedState.Transform(ref _cts, state => state switch | |
{ | |
null => new CancellationTokenSource(), | |
not null => state, | |
}); | |
newState!.Cancel(); | |
} | |
/// <summary> | |
/// Resets this instance to an uncancelled state. | |
/// </summary> | |
public void Reset() | |
{ | |
InterlockedState.Transform(ref _cts, state => state switch | |
{ | |
{ IsCancellationRequested: true } => null, | |
{ IsCancellationRequested: false } => state, | |
null => null, | |
}); | |
} | |
/// <summary> | |
/// If <c>null</c>, this instance is not canceled. If not <c>null</c>, the <see cref="CancellationTokenSource"/> may or may not be canceled. | |
/// </summary> | |
private CancellationTokenSource? _cts; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment