• 用户模式构造-互锁构造


      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服务器请求之后。
  • 相关阅读:
    AWS Redshift 采坑记
    EF Core 小工具
    Setup .net core EF
    Bat 使用MSBuild 制作发布包 (更新20180713)
    Https web Api 拉取数据踩坑记录
    C# 后台程序 通过批处理进行监控
    C#计算日期步进
    IIS 预热 (8.0及8.0以上版本)
    MSBuild 执行文档,关于使用命令行编译
    基于Bamboo的CI配置汇总(.Net Web及Api)
  • 原文地址:https://www.cnblogs.com/xuejietong/p/8992710.html
Copyright © 2020-2023  润新知