Skip to content

Instantly share code, notes, and snippets.

@davidfowl
Created October 11, 2022 02:53
Show Gist options
  • Save davidfowl/ba2a3da76784793a2ce3030afc5fc735 to your computer and use it in GitHub Desktop.
Save davidfowl/ba2a3da76784793a2ce3030afc5fc735 to your computer and use it in GitHub Desktop.
A sample showing how to schedule work on a single thread
using System.Collections.Concurrent;
using System.Threading.Channels;
var channel = Channel.CreateUnbounded<int>();
var syncContext = new SingleThreadedSyncContext();
syncContext.Post(async _ =>
{
await foreach (var item in channel.Reader.ReadAllAsync())
{
Console.WriteLine(Environment.CurrentManagedThreadId);
}
},
null);
for (int i = 0; ; i++)
{
await channel.Writer.WriteAsync(i);
Thread.Sleep(1000);
}
public class SingleThreadedSyncContext : SynchronizationContext
{
private readonly BlockingCollection<(SendOrPostCallback Callback, object? State)> _queue = new();
private readonly Thread _thread;
public SingleThreadedSyncContext()
{
_thread = new(RunQueue!);
_thread.Start();
}
public override void Post(SendOrPostCallback d, object? state)
{
_queue.Add((d, state));
}
private void RunQueue(object state)
{
SetSynchronizationContext(this);
foreach (var (d, s) in _queue.GetConsumingEnumerable())
{
d(s);
if (Current != this)
{
// Set the sync context in case the callback changed it
SetSynchronizationContext(this);
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment