using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Transactions;
namespace AsyncTest
{
/// <summary>Provides a SynchronizationContext that's single-threaded.</summary>
public class SingleThreadSynchronizationContext : SynchronizationContext
{
/// <summary>The queue of work items.</summary>
private readonly BlockingCollection<KeyValuePair<SendOrPostCallback, object>> m_queue =
new BlockingCollection<KeyValuePair<SendOrPostCallback, object>>();
/// <summary>The processing thread.</summary>
private readonly Thread m_thread = Thread.CurrentThread;
/// <summary>Dispatches an asynchronous message to the synchronization context.</summary>
/// <param name="d">The System.Threading.SendOrPostCallback delegate to call.</param>
/// <param name="state">The object passed to the delegate.</param>
public override void Post(SendOrPostCallback d, object state)
{
if (d == null) throw new ArgumentNullException("d");
m_queue.Add(new KeyValuePair<SendOrPostCallback, object>(d, state));
}
/// <summary>Not supported.</summary>
public override void Send(SendOrPostCallback d, object state)
{
throw new NotSupportedException("Synchronously sending is not supported.");
}
/// <summary>Runs an loop to process all queued work items.</summary>
public void RunOnCurrentThread()
{
foreach (var workItem in m_queue.GetConsumingEnumerable())
workItem.Key(workItem.Value);
}
/// <summary>Notifies the context that no more work will arrive.</summary>
public void Complete() { m_queue.CompleteAdding(); }
}
class Program
{
public static void Run(Func<Task> func)
{
var prevCtx = SynchronizationContext.Current;
try
{
var syncCtx = new SingleThreadSynchronizationContext();
//var syncCtx = new System.Windows.Threading.DispatcherSynchronizationContext();
SynchronizationContext.SetSynchronizationContext(syncCtx);
var t = func();
t.ContinueWith(
delegate { syncCtx.Complete(); }, TaskScheduler.Default);
syncCtx.RunOnCurrentThread();
//var frame = new System.Windows.Threading.DispatcherFrame();
//t.ContinueWith(_ => { frame.Continue = false; },
// TaskScheduler.Default);
//System.Windows.Threading.Dispatcher.PushFrame(frame);
t.GetAwaiter().GetResult();
}
finally { SynchronizationContext.SetSynchronizationContext(prevCtx); }
}
static async Task TestStuff(int nb)
{
Console.WriteLine("Entering teststuff " + Thread.CurrentThread.ManagedThreadId);
using (var scope = new TransactionScope())
{
int wait = 1000 + nb;
await Task.Delay(wait);
scope.Complete();
}
Console.WriteLine("Leaving teststuff " + Thread.CurrentThread.ManagedThreadId);
}
static void Main(string[] args)
{
Run(async delegate
{
var tasks = new Task[10];
for (int i = 0; i < 10; i++)
{
tasks[i] = TestStuff(i);
}
await Task.WhenAll(tasks);
});
Console.ReadLine();
}
}
}