Skip to content

Instantly share code, notes, and snippets.

@Xorcerer
Last active November 17, 2022 03:47
Show Gist options
  • Save Xorcerer/6505468 to your computer and use it in GitHub Desktop.
Save Xorcerer/6505468 to your computer and use it in GitHub Desktop.
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Collections.Concurrent;
using System.Collections.Generic;
namespace TestSynchronizationContext
{
class SingleThreadSynchronizationContext : SynchronizationContext
{
BlockingCollection<Action> _queue = new BlockingCollection<Action>();
public override void Post(SendOrPostCallback d, object state)
{
Console.WriteLine("Posted from thread: {0}, {1}", Thread.CurrentThread.ManagedThreadId, DateTime.Now);
_queue.Add(() => d(state));
}
public override void Send(SendOrPostCallback d, object state)
{
throw new NotImplementedException();
}
public void InvokeCallbacks()
{
Action a;
while (_queue.TryTake(out a, Timeout.Infinite))
a();
Console.WriteLine("InvokeCallbacks exited.");
}
public void Complete()
{
_queue.CompleteAdding();
Console.WriteLine("Completed.");
}
public static void Run(Func<Task> func)
{
var prevCtx = SynchronizationContext.Current;
try
{
var syncCtx = new SingleThreadSynchronizationContext();
SynchronizationContext.SetSynchronizationContext(syncCtx);
Task main = func();
main.ContinueWith(t => syncCtx.Complete(), TaskScheduler.Default);
syncCtx.InvokeCallbacks();
main.GetAwaiter().GetResult();
}
finally { SynchronizationContext.SetSynchronizationContext(prevCtx); }
}
}
class MainClass
{
public static void Main()
{
Task.Run(() => Run()).Wait();
}
public static void Run()
{
SingleThreadSynchronizationContext.Run(() => DemoAsync());
//DemoAsync().Wait();
}
static async Task DemoAsync()
{
var d = new Dictionary<int, int>();
for (int i = 0; i < 10; i++)
{
int id = Thread.CurrentThread.ManagedThreadId;
int count;
d[id] = d.TryGetValue(id, out count) ? count + 1 : 1;
await Task.Delay(100);
}
foreach (var pair in d) Console.WriteLine(pair);
}
public static async Task F()
{
PrintStatus();
SynchronizationContext.SetSynchronizationContext(new SingleThreadSynchronizationContext());
PrintStatus();
await Task.Delay(100);
PrintStatus();
}
public static void PrintStatus()
{
Console.WriteLine("Id {0}, in thread pool {1}, context {2}.",
Thread.CurrentThread.ManagedThreadId,
Thread.CurrentThread.IsThreadPoolThread,
SynchronizationContext.Current);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment