解决在同步方法中使用异步方法产生的线程死锁(死锁的主要原因是因为代码中线程对上下文的争夺)
1 /// <summary> 2 /// 此类作用:解决在同步方法中使用异步方法产生的线程死锁 3 /// 死锁的主要原因是因为代码中线程对上下文的争夺 4 /// </summary> 5 public static class AsyncExtend 6 { 7 /// <summary> 8 /// 同步执行一个void类型的返回值操作 9 /// </summary> 10 /// <param name="task">Task method to execute</param> 11 public static void RunSync(Func<Task> task) 12 { 13 var oldContext = SynchronizationContext.Current; 14 var synch = new ExclusiveSynchronizationContext(); 15 SynchronizationContext.SetSynchronizationContext(synch); 16 synch.Post(async _ => 17 { 18 try 19 { 20 await task(); 21 } 22 catch (Exception e) 23 { 24 synch.InnerException = e; 25 throw; 26 } 27 finally 28 { 29 synch.EndMessageLoop(); 30 } 31 }, null); 32 synch.BeginMessageLoop(); 33 34 SynchronizationContext.SetSynchronizationContext(oldContext); 35 } 36 37 /// <summary> 38 /// 同步执行一个Task《T》的异步任务 39 /// </summary> 40 /// <typeparam name="T">Return Type</typeparam> 41 /// <param name="task">Task《T》 method to execute</param> 42 /// <returns></returns> 43 public static T RunSync<T>(Func<Task<T>> task) 44 { 45 var oldContext = SynchronizationContext.Current; 46 var synch = new ExclusiveSynchronizationContext(); 47 SynchronizationContext.SetSynchronizationContext(synch); 48 T ret = default(T); 49 synch.Post(async _ => 50 { 51 try 52 { 53 ret = await task(); 54 } 55 catch (Exception e) 56 { 57 synch.InnerException = e; 58 throw; 59 } 60 finally 61 { 62 synch.EndMessageLoop(); 63 } 64 }, null); 65 synch.BeginMessageLoop(); 66 SynchronizationContext.SetSynchronizationContext(oldContext); 67 return ret; 68 } 69 70 /// <summary> 71 /// 带异常的异步上下文 72 /// </summary> 73 private class ExclusiveSynchronizationContext : SynchronizationContext 74 { 75 private bool _done; 76 public Exception InnerException { get; set; } 77 readonly AutoResetEvent _workItemsWaiting = new AutoResetEvent(false); 78 79 private readonly Queue<Tuple<SendOrPostCallback, object>> _items = 80 new Queue<Tuple<SendOrPostCallback, object>>(); 81 82 public override void Send(SendOrPostCallback d, object state) 83 { 84 throw new NotSupportedException("We cannot send to our same thread"); 85 } 86 87 public override void Post(SendOrPostCallback d, object state) 88 { 89 lock (_items) 90 { 91 _items.Enqueue(Tuple.Create(d, state)); 92 } 93 _workItemsWaiting.Set(); 94 } 95 96 public void EndMessageLoop() 97 { 98 Post(_ => _done = true, null); 99 } 100 101 public void BeginMessageLoop() 102 { 103 while (!_done) 104 { 105 Tuple<SendOrPostCallback, object> task = null; 106 lock (_items) 107 { 108 if (_items.Count > 0) 109 { 110 task = _items.Dequeue(); 111 } 112 } 113 if (task != null) 114 { 115 task.Item1(task.Item2); 116 if (InnerException != null) // the method threw an exeption 117 { 118 throw new AggregateException("AsyncExtend.Run method threw an exception.", InnerException); 119 } 120 } 121 else 122 { 123 _workItemsWaiting.WaitOne(); 124 } 125 } 126 } 127 128 public override SynchronizationContext CreateCopy() 129 { 130 return this; 131 } 132 } 133 }