用户模式构造-互锁构造

  1     internal enum CoordinationStatus { AllDone, Timeout, Cancel }
  2 
  3     /// <summary>
  4     /// 协调所有异步操作
  5     /// </summary>
  6     internal sealed class AsyncCoordinator
  7     {
  8         //AllBegun内部调用JustEnded来递减
  9         private int m_opCount = 1;
 10         //0为false,1为true
 11         private int m_statusReported = 0;
 12 
 13         private Action<CoordinationStatus> m_callback;
 14 
 15         private Timer m_timer;
 16 
 17         /// <summary>
 18         /// 该方法必须在发起一个操作之前调用
 19         /// </summary>
 20         /// <param name="opsToAdd"></param>
 21         public void AboutToBegin(int opsToAdd = 1)
 22         {
 23             //为多个线程共享的变量提供原子操作
 24             //对两个 32 位整数进行求和并用和替换第一个整数,上述操作作为一个原子操作完成
 25             // 参数:
 26             //   location1:
 27             //     一个变量,包含要添加的第一个值。 两个值的总和存储在 location1。
 28             //
 29             //   value:
 30             //     要添加到整数的值 location1。
 31             //
 32             // 返回结果:
 33             //     新值存储在 location1。
 34             Interlocked.Add(ref m_opCount, opsToAdd);
 35         }
 36 
 37         /// <summary>
 38         /// 该方法必须在处理好一个操作的结果之后调用
 39         /// </summary>
 40         public void JustEnded()
 41         {
 42             //为多个线程共享的变量提供原子操作
 43             //以原子操作的形式递减指定变量的值并存储结果
 44             // 参数:
 45             //   location:
 46             //     其值要递减的变量。
 47             //
 48             // 返回结果:
 49             //     递减的值。
 50             if (Interlocked.Decrement(ref m_opCount) == 0)
 51             {
 52                 ReportStatus(CoordinationStatus.AllDone);
 53             }
 54         }
 55 
 56         /// <summary>
 57         /// 该方法必须在发起所有操作之后调用
 58         /// </summary>
 59         /// <param name="action"></param>
 60         /// <param name="timeout"></param>
 61         public void AllBegun(Action<CoordinationStatus> action, int timeout = Timeout.Infinite)
 62         {
 63             m_callback = action;
 64 
 65             //若不是无限等待
 66             if (timeout != Timeout.Infinite)
 67             {
 68                 m_timer = new Timer(TimeExpired, null, timeout, Timeout.Infinite);
 69             }
 70 
 71             JustEnded();
 72         }
 73 
 74         /// <summary>
 75         /// 取消
 76         /// </summary>
 77         public void Cancel()
 78         {
 79             ReportStatus(CoordinationStatus.Cancel);
 80         }
 81 
 82         /// <summary>
 83         /// 超时
 84         /// </summary>
 85         /// <param name="obj"></param>
 86         private void TimeExpired(object obj)
 87         {
 88             ReportStatus(CoordinationStatus.Timeout);
 89         }
 90 
 91         /// <summary>
 92         /// 报告状态
 93         /// </summary>
 94         /// <param name="status"></param>
 95         private void ReportStatus(CoordinationStatus status)
 96         {
 97             //如果状态从未报告过就报告它,否则忽略它
 98             //为多个线程共享的变量提供原子操作
 99             //以原子操作的形式,将 32 位有符号整数设置为指定的值并返回原始值
100             // 参数:
101             //   location1:
102             //     要设置为指定值的变量。
103             //
104             //   value:
105             //     location1 参数要设置成的值。
106             //
107             // 返回结果:
108             //     location1 的原始值。
109             if (Interlocked.Exchange(ref m_statusReported, 1) == 0)
110             {
111                 m_callback(status);
112             }
113         }
114     }
115 
116     internal sealed class MultiWebRequests
117     {
118         //用于协调所有异步操作
119         private AsyncCoordinator m_AsyncCoordinator = new AsyncCoordinator();
120 
121         //想要查询的Web服务器及其响应(异常或int)的集合
122         //多个线程访问该字典时不需要同步进行,因为构造后键是只读的
123         private Dictionary<string, object> m_servers = new Dictionary<string, object>
124         {
125             {"http://referencesource.microsoft.com/",null },
126             {"https://msdn.microsoft.com/zh-CN/",null },
127             {"https://www.microsoft.com/net",null },
128             {"http://www.songtaste.com/",null }
129         };
130 
131         public MultiWebRequests(int timeout = Timeout.Infinite)
132         {
133             //以异步方式,一次性发起所有请求
134             var httpClient = new HttpClient();
135             foreach (var server in m_servers.Keys)
136             {
137                 m_AsyncCoordinator.AboutToBegin(1);
138                 httpClient.GetByteArrayAsync(server).ContinueWith(task => ComputeResult(server, task));
139             }
140 
141             //告诉AsyncCoordinator 所有操作均已发起
142             //并在所有操作完成或调用Cancel或超时时调用AllDone
143             m_AsyncCoordinator.AllBegun(AllDone, timeout);
144         }
145 
146         private void ComputeResult(string server, Task<byte[]> task)
147         {
148             Object result;
149             if (task.Exception != null)
150             {
151                 result = task.Exception.InnerException;
152             }
153             else
154             {
155                 result = task.Result.Length;
156             }
157 
158             //保存结果,指出1个操作完成
159             m_servers[server] = result;
160             m_AsyncCoordinator.JustEnded();
161         }
162 
163         /// <summary>
164         /// 调用这个方法指出结果已无关紧要
165         /// </summary>
166         public void Cancel()
167         {
168             m_AsyncCoordinator.Cancel();
169         }
170 
171         //所有服务器都响应、调用了Cancel或发生了超时就调用该方法
172         private void AllDone(CoordinationStatus status)
173         {
174             switch (status)
175             {
176                 case CoordinationStatus.AllDone:
177                     Console.WriteLine("Completed");
178                     foreach (var server in m_servers)
179                     {
180                         Console.Write("{0} ", server.Key);
181                         object result = server.Value;
182                         if (result is Exception)
183                         {
184                             Console.WriteLine("Failed due to {0}.", result.GetType().Name);
185                         }
186                         else
187                         {
188                             Console.WriteLine("Returned {0:N0} bytes.", result);
189                         }
190                     }
191                     break;
192                 case CoordinationStatus.Timeout:
193                     Console.WriteLine("Timeout");
194                     break;
195                 case CoordinationStatus.Cancel:
196                     Console.WriteLine("Cancelled");
197                     break;
198                 default:
199                     break;
200             }
201         }
202     }
m_opCount字段初始化为1(而非0),执行构造器方法的线程在发出Web服务器请求期间,由于m_opCount为1,所以能保证AllDone不会被调用,构造器调用AllBegun之前,m_opCount不可能变成0。构造器调用AllBegun时,AllBegun内部调用JustEnded来递减m_opCount,所以事实上撤销了把它初始化成1的效果,现在m_opCount能变成0了,但只能是在发起了所有Web服务器请求之后。

posted on 2018-05-12 11:15  庭前花满留晚照  阅读(306)  评论(0)    收藏  举报

导航