using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Threading.Tasks;
public async static Task Main()
var scheduler = new SingleThreadTaskScheduler(default);
var tasks = Enumerable.Range(0, 100).Select(i =>
TaskCreationOptions.DenyChildAttach,
var threadIds = await Task.WhenAll(tasks);
Console.WriteLine($"There were {threadIds.Distinct().Count()} different threads involved.");
static int DoSomething(object obj)
int threadId = Thread.CurrentThread.ManagedThreadId;
public sealed class SingleThreadTaskScheduler : TaskScheduler
private static bool _isExecuting;
private readonly CancellationToken _cancellationToken;
private readonly BlockingCollection<Task> _taskQueue;
private readonly Lazy<Thread> _singleThread;
public override int MaximumConcurrencyLevel => 1;
public SingleThreadTaskScheduler(CancellationToken cancellationToken)
this._cancellationToken = cancellationToken;
this._taskQueue = new BlockingCollection<Task>();
_singleThread = new Lazy<Thread>(() =>
var thread = new Thread(RunOnCurrentThread) { Name = "STTS Thread", IsBackground = true };
private void RunOnCurrentThread()
foreach (var task in _taskQueue.GetConsumingEnumerable(_cancellationToken))
catch (OperationCanceledException)
protected override IEnumerable<Task> GetScheduledTasks() => _taskQueue.ToList();
protected override void QueueTask(Task task)
_taskQueue.Add(task, _cancellationToken);
catch (OperationCanceledException)
protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
if (taskWasPreviouslyQueued) return false;
return _isExecuting && TryExecuteTask(task);