Created
October 11, 2022 02:53
-
-
Save davidfowl/ba2a3da76784793a2ce3030afc5fc735 to your computer and use it in GitHub Desktop.
A sample showing how to schedule work on a single thread
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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