using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading.Tasks;
private sealed class SingleThreadSynchronizationContext : SynchronizationContext
private readonly BlockingCollection<KeyValuePair<SendOrPostCallback, object>> m_queue =
new BlockingCollection<KeyValuePair<SendOrPostCallback, object>>();
public override void Post(SendOrPostCallback d, object state)
m_queue.Add(new KeyValuePair<SendOrPostCallback, object>(d, state));
public void RunOnCurrentThread()
KeyValuePair<SendOrPostCallback, object> workItem;
while (m_queue.TryTake(out workItem, Timeout.Infinite))
workItem.Key(workItem.Value);
m_queue.CompleteAdding();
public static void Run(Func<Task> func)
var prevCtx = SynchronizationContext.Current;
var syncCtx = new SingleThreadSynchronizationContext();
SynchronizationContext.SetSynchronizationContext(syncCtx);
delegate { syncCtx.Complete(); }, TaskScheduler.Default);
syncCtx.RunOnCurrentThread();
t.GetAwaiter().GetResult();
SynchronizationContext.SetSynchronizationContext(prevCtx);
public static void Main()
static async Task DemoAsync()
var d = new Dictionary<int, int>();
for (int i = 0; i < 10000; i++)
int id = Thread.CurrentThread.ManagedThreadId;
d[id] = d.TryGetValue(id, out count) ? count + 1 : 1;