| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192 |
- 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
- {
- /// <summary>
- /// 同步调用异步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
- /// </summary>
- public static class AsyncHelper
- {
- /// <summary>
- /// Execute's an async Task<T> method which has a void return value synchronously
- /// </summary>
- /// <param name="task">Task<T> method to execute</param>
- public static void RunSync(Func<Task> 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);
- }
- /// <summary>
- /// Execute's an async Task<T> method which has a T return type synchronously
- /// </summary>
- /// <typeparam name="T">Return Type</typeparam>
- /// <param name="task">Task<T> method to execute</param>
- /// <returns></returns>
- public static T RunSync<T>(Func<Task<T>> 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<Tuple<SendOrPostCallback, object>> items =
- new Queue<Tuple<SendOrPostCallback, object>>();
- 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<SendOrPostCallback, object> 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;
- }
- }
- }
- /// <summary>
- /// Class AsyncHelper.
- /// </summary>
- public static class AsyncHelper_
- {
- private static readonly TaskFactory MyTaskFactory = new TaskFactory(CancellationToken.None, TaskCreationOptions.None, TaskContinuationOptions.None, TaskScheduler.Default);
- /// <summary>在同步方法中不死锁方式调用异步方法</summary>
- public static TResult RunSync<TResult>(Func<Task<TResult>> 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();
- }
- /// <summary>在同步方法中不死锁方式调用异步方法</summary>
- public static void RunSync(Func<Task> func)
- {
- var currentUiCulture = CultureInfo.CurrentUICulture;
- var currentCulture = CultureInfo.CurrentCulture;
- MyTaskFactory.StartNew(() =>
- {
- Thread.CurrentThread.CurrentCulture = currentCulture;
- Thread.CurrentThread.CurrentUICulture = currentUiCulture;
- return func();
- })
- .Unwrap()
- .GetAwaiter()
- .GetResult();
- }
- }
- }
|