using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Linq; using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; namespace MadRunFabric.Common { /// /// 同步调用异步async防止死锁方案 /// /// 当前代码地址 /// https://github.com/tejacques/AsyncBridge/blob/master/src/AsyncBridge/AsyncHelper.cs /// /// https://github.com/tejacques/AsyncBridge /// http://stackoverflow.com/questions/5095183/how-would-i-run-an-async-taskt-method-synchronously /// https://social.msdn.microsoft.com/Forums/en-US/163ef755-ff7b-4ea5-b226-bbe8ef5f4796/is-there-a-pattern-for-calling-an-async-method-synchronously?forum=async /// public static class AsyncHelper { /// /// Execute's an async Task method which has a void return value synchronously /// /// Task method to execute public static void RunSync(Func task) { var oldContext = SynchronizationContext.Current; var synch = new ExclusiveSynchronizationContext(); SynchronizationContext.SetSynchronizationContext(synch); synch.Post(async _ => { try { await task(); } catch (Exception e) { synch.InnerException = e; throw; } finally { synch.EndMessageLoop(); } }, null); synch.BeginMessageLoop(); SynchronizationContext.SetSynchronizationContext(oldContext); } /// /// Execute's an async Task method which has a T return type synchronously /// /// Return Type /// Task method to execute /// public static T RunSync(Func> task) { var oldContext = SynchronizationContext.Current; var synch = new ExclusiveSynchronizationContext(); SynchronizationContext.SetSynchronizationContext(synch); T ret = default(T); synch.Post(async _ => { try { ret = await task(); } catch (Exception e) { synch.InnerException = e; throw; } finally { synch.EndMessageLoop(); } }, null); synch.BeginMessageLoop(); SynchronizationContext.SetSynchronizationContext(oldContext); return ret; } private class ExclusiveSynchronizationContext : SynchronizationContext { private bool done; public Exception InnerException { get; set; } readonly AutoResetEvent workItemsWaiting = new AutoResetEvent(false); readonly Queue> items = new Queue>(); public override void Send(SendOrPostCallback d, object state) { throw new NotSupportedException("We cannot send to our same thread"); } public override void Post(SendOrPostCallback d, object state) { lock (items) { items.Enqueue(Tuple.Create(d, state)); } workItemsWaiting.Set(); } public void EndMessageLoop() { Post(_ => done = true, null); } public void BeginMessageLoop() { while (!done) { Tuple task = null; lock (items) { if (items.Count > 0) { task = items.Dequeue(); } } if (task != null) { task.Item1(task.Item2); if (InnerException != null) // the method threw an exeption { throw new AggregateException($"AsyncHelpers.Run Exception.{InnerException.Message}", InnerException); } } else { workItemsWaiting.WaitOne(); } } } public override SynchronizationContext CreateCopy() { return this; } } } /// /// Class AsyncHelper. /// public static class AsyncHelper_ { private static readonly TaskFactory MyTaskFactory = new TaskFactory(CancellationToken.None, TaskCreationOptions.None, TaskContinuationOptions.None, TaskScheduler.Default); /// 在同步方法中不死锁方式调用异步方法 public static TResult RunSync(Func> func) { var currentUiCulture = CultureInfo.CurrentUICulture; var currentCulture = CultureInfo.CurrentCulture; return MyTaskFactory.StartNew(() => { Thread.CurrentThread.CurrentCulture = currentCulture; Thread.CurrentThread.CurrentUICulture = currentUiCulture; return func(); }) .Unwrap() .GetAwaiter() .GetResult(); } /// 在同步方法中不死锁方式调用异步方法 public static void RunSync(Func func) { var currentUiCulture = CultureInfo.CurrentUICulture; var currentCulture = CultureInfo.CurrentCulture; MyTaskFactory.StartNew(() => { Thread.CurrentThread.CurrentCulture = currentCulture; Thread.CurrentThread.CurrentUICulture = currentUiCulture; return func(); }) .Unwrap() .GetAwaiter() .GetResult(); } } }