using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;
private static readonly Random rng = new Random();
public static async Task Main()
var cts = new CancellationTokenSource(TimeSpan.FromMinutes(5));
var tasks = Enumerable.Range(1, 16)
while (cts.Token.IsCancellationRequested == false)
await mgr.DoAllTheThings(x);
tasks.Add(Task.Run( async () =>
while (cts.Token.IsCancellationRequested == false)
await mgr.UpdateConfig(new Configuration
DelayMilliseconds = rng.Next(50, 100),
DelayMilliseconds2 = rng.Next(50, 200)
await Task.WhenAll(tasks);
public sealed class Configuration
public int DelayMilliseconds { get; set; }
public int DelayMilliseconds2 { get; set; }
public sealed class Manager : BaseClass<Configuration>
private int delayMilliseconds = 1000;
public async Task DoAllTheThings(int id)
var sw = Stopwatch.StartNew();
await Task.Delay(delayMilliseconds);
Console.WriteLine($"{nameof(DoAllTheThings)} #{id} complete in ({sw.ElapsedMilliseconds}ms)");
protected override Task OnConfigChanged(Configuration d)
delayMilliseconds = d.DelayMilliseconds;
return Task.Delay(d.DelayMilliseconds2);
public abstract class BaseClass<TConfig>
where TConfig: class, new()
protected Task Initialization
return padlock.WaitAsync()
.ContinueWith(_ => initialization)
.ContinueWith(_ => padlock.Release(1));
private Task initialization;
private readonly SemaphoreSlim padlock;
private readonly SettingsManager settingsManager;
padlock = new SemaphoreSlim(1, 1);
settingsManager = new SettingsManager();
initialization = Initialize();
public Task UpdateConfig(TConfig config)
return padlock.WaitAsync()
initialization = Initialize(config);
return Task.CompletedTask;
.ContinueWith(_ => padlock.Release(1))
.ContinueWith(_ => initialization);
protected abstract Task OnConfigChanged(TConfig d);
private async Task Initialize(TConfig config = null)
if (initialization is { IsCompleted: false })
var newConfig = config ?? await settingsManager.GetAsync<TConfig>();
await OnConfigChanged(newConfig);
public sealed class SettingsManager
public Task<T> GetAsync<T>()
return Task.FromResult<T>(new T());