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 }