Skip to content

Instantly share code, notes, and snippets.

@distantcam
Last active February 3, 2016 09:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save distantcam/b4e0efaea051da58a77c to your computer and use it in GitHub Desktop.
Save distantcam/b4e0efaea051da58a77c to your computer and use it in GitHub Desktop.
An example using `Task.WhenAll` that runs all the tasks on the same thread.
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static void Main()
{
AsyncPump.Run(async delegate
{
await MainAsync();
});
Console.ReadLine();
}
private static async Task MainAsync()
{
var tasks = new List<Task>();
var d = new Dictionary<int, int>();
for (int i = 0; i < 10000; i++)
{
Func<Task> taskFunc = () =>
{
int id = Thread.CurrentThread.ManagedThreadId;
int count;
d[id] = d.TryGetValue(id, out count) ? count + 1 : 1;
return Task.FromResult(0);
};
await Task.Yield();
tasks.Add(taskFunc());
}
await Task.WhenAll(tasks);
foreach (var pair in d) Console.WriteLine(pair);
}
}
class AsyncPump
{
public static void Run(Func<Task> func)
{
var prevCtx = SynchronizationContext.Current;
try
{
var syncCtx = new SingleThreadSynchronizationContext();
SynchronizationContext.SetSynchronizationContext(syncCtx);
var t = func();
t.ContinueWith(delegate { syncCtx.Complete(); }, TaskScheduler.Default);
syncCtx.RunOnCurrentThread();
t.GetAwaiter().GetResult();
}
finally { SynchronizationContext.SetSynchronizationContext(prevCtx); }
}
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);
}
public void Complete()
{
m_queue.CompleteAdding();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment