C# 一个代码的输出有问题,流程没问题

namespace ConsoleApp21
{    
                                    //完成,超时,取消
    internal enum CoordinationStatus { AllDone,Timeout,Cancel };  //协调状态

    internal sealed class AsyncCoordinator
    {
        int m_opCount = 1;   //计数
        int m_statusReported = 0;  //状态报告
        Action<CoordinationStatus> m_callback;  //回调
        Timer m_timer;   //时间
          
        public void AboutToBegin(int opsToAdd=1)  //开始
        {  //每次增加opsToAdd
            Interlocked.Add(ref m_opCount, opsToAdd);
        }
        public void JustEnded()//结束
        {
            if (Interlocked.Decrement(ref m_opCount) == 0)   //返回递减后的值,查看是否为0
                ReportStatus(CoordinationStatus.AllDone);
        }

        public void AllBegun(Action<CoordinationStatus> callback
            , int timeout = Timeout.Infinite)
        {
            m_callback = callback;
            if (timeout != Timeout.Infinite)  //如果传递的参数不等于超时值,调用回调一次
                m_timer = new Timer(TimeExpired, null, timeout, Timeout.Infinite);
            JustEnded();  //递减计数
        }
        void TimeExpired(object o)  //过期(超时)
        {
            ReportStatus(CoordinationStatus.Timeout);
        }
        public void Cancel()
        {
            ReportStatus(CoordinationStatus.Cancel);
        }

        void ReportStatus(CoordinationStatus status)
        {
            if (Interlocked.Exchange(ref m_statusReported, 1) == 0) //只调用1次
                m_callback(status);
        }
    }

    internal sealed class MultiWebRequests
    {
        AsyncCoordinator m_ac = new AsyncCoordinator();
        Dictionary<string, object> m_servers = new Dictionary<string, object>
        {
            {  "http://Wintellect.com/",null },
            { "http://Microsoft.com/",null},
            { "http://1.1.1.1/",null}
        };


        public MultiWebRequests(int timeout = Timeout.Infinite)//Web请求
        {
            HttpClient httpClient = new HttpClient();
            foreach (string server in m_servers.Keys)
            {
                m_ac.AboutToBegin(1);  //计数+1,每次
                httpClient.GetByteArrayAsync(server).ContinueWith
                    (task => ComputeResult(server, task));
            }
            m_ac.AllBegun(AllDone, timeout);   //注册回调方法,传递是否 触发 参数
        }
        void ComputeResult(string server, Task<byte[]> task) //延续任务
        {
            object result = null;
            if (task.Exception != null)  //引发了异常
                result = task.Exception.InnerException;   //result装载异常
            else  //未引发异常
                result = task.Result.Length;  //装载数组的长度
            m_servers[server] = result;  //查询字典
            m_ac.JustEnded();  //递减计数,递减为0触发报告
        }

        public void Cancel()  //取消
        {
            m_ac.Cancel();
        }

        void AllDone(CoordinationStatus status)
        {
            switch (status)
            {
                case CoordinationStatus.Cancel:
                    Console.WriteLine("取消");break;
                case CoordinationStatus.Timeout:
                    Console.WriteLine("超时");break;
                case CoordinationStatus.AllDone:
                    {
                        Console.WriteLine("完成");
                        foreach (var server in m_servers)
                        {
                            Console.Write("{0}", server.Key);
                            object result = server;
                            if (result is Exception) //如果装载了异常
                                Console.WriteLine(" 异常,{0}", result.GetType().Name);
                            else
                                Console.WriteLine(" 长度,{0}", result);                               
                        }
                        break;
                    }
            }
        }
    }
    class Myclass
    {
        static void Main()
        {
            MultiWebRequests t = new MultiWebRequests(1);
            t.Cancel();
            Console.ReadLine();
        }
    }
}

构造必然在调用t.cancel()前完成,
构造内部的m_ac.AllBegun(AllDone, timeout);
由于我构造的时候传递了一个超时参数 1 ,
m_timer = new Timer(TimeExpired, null, timeout, Timeout.Infinite); 必然会被调用,最后输出 超时
但是执行的时候输出值 有两种情况, 超时 或者 取消,
但是按流程取消的函数内部调用必然不会被调用,但是结果就是有可能取消先

为什么会这样???

阅读 1.7k
1 个回答

Timer是由线程池线程提供服务,你的m_timer = new Timer(TimeExpired, null, 1, Timeout.Infinite); 表示调用TimeExpired之前延迟1ms。所以是有可能在这1ms内cancel方法被执行的

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进