Let's say there is a library that handles events asynchronously, e.g. UDP broadcasting. I would like to be able to pass a delegate to this library and make sure that delegate is executed in the thread where it was defined.
public void Run(Action<string> action)
{
var PORT = 10000;
var udpClient = new UdpClient();
// Start listener
udpClient.Client.Bind(new IPEndPoint(IPAddress.Any, PORT));
var endpoint = new IPEndPoint(0, 0);
//var scheduler = TaskScheduler.Current; // No exception but executed in another thread
var scheduler = TaskScheduler.FromCurrentSynchronizationContext(); // Raises exception
Task.Factory.StartNew(() =>
{
while (true)
{
action(Encoding.UTF8.GetString(udpClient.Receive(ref endpoint)));
}
}, CancellationToken.None, TaskCreationOptions.None, scheduler);
// Start sender
var data = Encoding.UTF8.GetBytes("PING");
udpClient.Send(data, data.Length, "255.255.255.255", PORT);
var aTimer = new System.Timers.Timer();
aTimer.Elapsed += new ElapsedEventHandler(OnTimer);
aTimer.Interval = 1000;
aTimer.Enabled = true;
void OnTimer(object source, ElapsedEventArgs e)
{
var data = Encoding.UTF8.GetBytes("PONG");
udpClient.Send(data, data.Length, "255.255.255.255", PORT);
}
}
Then I check in which thread my delegate was executed.
Console.WriteLine("Start on Thread : " + Thread.CurrentThread.ManagedThreadId);
new Beacon().Run(response =>
{
Console.WriteLine("Continue on Thread : " + Thread.CurrentThread.ManagedThreadId);
});
If I use TaskScheduler.Current
nothing changes, the delegate is executed in another thread. If I use TaskScheduler.FromCurrentSynchronizationContext
, I get an exception below.
The current SynchronizationContext may not be used as a TaskScheduler
Questions
- Why I can't use synchronization context in .NET core or how to use it properly?
- Is there a better way of marshaling delegate call to the main thread?
- Are
BackgroundWorker
andEventLoopScheduler
obsolete now?