using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Threading.Tasks;
public static async Task Main()
using (CustomThreadPool scheduler = new())
await Task.Factory.StartNew(() => VerifyTaskSchedulerRemainsCustom(),
CancellationToken.None, TaskCreationOptions.DenyChildAttach,
Console.WriteLine($"Out: {TaskScheduler.Current}");
Console.WriteLine($"Finished");
private static async Task VerifyTaskSchedulerRemainsCustom()
Console.WriteLine($"1: {TaskScheduler.Current}");
Console.WriteLine($"2: {TaskScheduler.Current}");
await Task.Delay(100).ConfigureAwait(true);
Console.WriteLine($"3: {TaskScheduler.Current}");
Console.WriteLine($"4: {TaskScheduler.Current}");
Console.WriteLine($"5: {TaskScheduler.Current}");
await Task.Delay(100).ConfigureAwait(true);
Console.WriteLine($"6: {TaskScheduler.Current}");
public class CustomThreadPool : TaskScheduler, IDisposable
private readonly BlockingCollection<Task> _queue;
private readonly Thread[] _threads;
public CustomThreadPool(int threadsCount = 1)
_queue = new BlockingCollection<Task>();
_threads = Enumerable.Range(0, threadsCount).Select(_ => new Thread(() =>
foreach (var task in _queue.GetConsumingEnumerable())
}) { IsBackground = true }).ToArray();
Array.ForEach(_threads, t => t.Start());
protected override void QueueTask(Task task)
try { _queue.Add(task); }
catch (ObjectDisposedException)
ThreadPool.QueueUserWorkItem(_ => throw new TaskSchedulerException());
protected override bool TryExecuteTaskInline(Task task,
bool taskWasPreviouslyQueued)
if (Array.IndexOf(_threads, Thread.CurrentThread) < 0) return false;
return TryExecuteTask(task);
public override int MaximumConcurrencyLevel => _threads.Length;
protected override IEnumerable<Task> GetScheduledTasks() => _queue;
Array.ForEach(_threads, t => t.Join());