using System; using System.Collections.Generic; using System.Collections.Concurrent; using System.Threading; using System.Threading.Tasks; namespace IOB_UT_NEXT.Services.Core { public class SingleThreadTaskScheduler : TaskScheduler, IDisposable { #region Public Constructors 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 } #endregion Public Constructors #region Public Properties public override int MaximumConcurrencyLevel => 1; public SynchronizationContext SyncContext { get; private set; } #endregion Public Properties #region Public Methods public void Dispose() => _tasks.CompleteAdding(); #endregion Public Methods #region Protected Methods protected override IEnumerable GetScheduledTasks() => _tasks; protected override void QueueTask(Task task) => _tasks.Add(task); protected override bool TryExecuteTaskInline(Task task, bool prev) => Thread.CurrentThread == _thread && base.TryExecuteTask(task); #endregion Protected Methods #region Private Fields private readonly BlockingCollection _tasks = new BlockingCollection(); private readonly Thread _thread; #endregion Private Fields #region Private Classes private class SingleThreadSynchronizationContext : SynchronizationContext { #region Public Constructors public SingleThreadSynchronizationContext(SingleThreadTaskScheduler sch) => _sch = sch; #endregion Public Constructors #region Public Methods public override void Post(SendOrPostCallback d, object state) => Task.Factory.StartNew(() => d(state), CancellationToken.None, TaskCreationOptions.None, _sch); #endregion Public Methods #region Private Fields private readonly SingleThreadTaskScheduler _sch; #endregion Private Fields } #endregion Private Classes } }