using System; using System.Collections.Generic; using System.Collections.Concurrent; using System.Threading; using System.Threading.Tasks; public class SingleThreadTaskScheduler : TaskScheduler, IDisposable { private readonly BlockingCollection _tasks = new BlockingCollection(); private readonly Thread _thread; public SynchronizationContext SyncContext { get; private set; } public SingleThreadTaskScheduler(string threadName) { var tcs = new TaskCompletionSource(); _thread = new Thread(() => { // Creiamo il contesto di sincronizzazione personalizzato SyncContext = new SingleThreadSynchronizationContext(this); SynchronizationContext.SetSynchronizationContext(SyncContext); tcs.SetResult(true); foreach (var task in _tasks.GetConsumingEnumerable()) { base.TryExecuteTask(task); } }) { IsBackground = true, Name = threadName }; _thread.Start(); tcs.Task.Wait(); // Aspetta che il thread sia pronto col suo contesto } private class SingleThreadSynchronizationContext : SynchronizationContext { private readonly SingleThreadTaskScheduler _sch; public SingleThreadSynchronizationContext(SingleThreadTaskScheduler sch) => _sch = sch; public override void Post(SendOrPostCallback d, object state) => Task.Factory.StartNew(() => d(state), CancellationToken.None, TaskCreationOptions.None, _sch); } protected override void QueueTask(Task task) => _tasks.Add(task); protected override bool TryExecuteTaskInline(Task task, bool prev) => Thread.CurrentThread == _thread && base.TryExecuteTask(task); protected override IEnumerable GetScheduledTasks() => _tasks; public override int MaximumConcurrencyLevel => 1; public void Dispose() => _tasks.CompleteAdding(); }