解决在同步方法中使用异步方法产生的线程死锁(死锁的主要原因是因为代码中线程对上下文的争夺)

  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 }

 

posted @ 2017-01-20 10:12  小小的菜鸟程序员  阅读(571)  评论(0编辑  收藏  举报