using System.Diagnostics;
using System.Threading.Tasks;
using System.Threading.Tasks.Sources;
public static void Main()
using CancellationTokenSource cts = new();
var pausation = new Pausation();
while (!cts.IsCancellationRequested)
ValueTask waitTask = pausation.WaitWhilePausedAsync();
if (!waitTask.IsCompleted) pausedCount++;
Console.WriteLine($"Worker loops: {workerLoops:#,0}, paused: {pausedCount:#,0} times");
Task worker = StartWorker();
long controllerLoops = 0;
Stopwatch stopwatch = Stopwatch.StartNew();
while (stopwatch.ElapsedMilliseconds < 1000)
Console.WriteLine($"Controller loops: {controllerLoops:#,0}");
worker.GetAwaiter().GetResult();
public class Pausation : IValueTaskSource
private ManualResetValueTaskSourceCore<bool> _source;
public Pausation() => _source.RunContinuationsAsynchronously = true;
_source.SetResult(default);
public ValueTask WaitWhilePausedAsync()
if (!_paused) return ValueTask.CompletedTask;
return new ValueTask(this, _source.Version);
void IValueTaskSource.GetResult(short token)
_source.GetResult(token);
ValueTaskSourceStatus IValueTaskSource.GetStatus(short token)
return _source.GetStatus(token);
void IValueTaskSource.OnCompleted(Action<object> continuation, object state,
short token, ValueTaskSourceOnCompletedFlags flags)
_source.OnCompleted(continuation, state, token, flags);
private class Pausation_AsyncEx
private readonly PauseTokenSource _pts = new();
public void Pause() => _pts.IsPaused = true;
public void Resume() => _pts.IsPaused = false;
public ValueTask WaitWhilePausedAsync() => new(_pts.Token.WaitWhilePausedAsync());