代码之家  ›  专栏  ›  技术社区  ›  Adrian

C#代码在进入DEBUG构建中的前几行之前执行

  •  0
  • Adrian  · 技术社区  · 3 年前

    我不知所措。我有一个任务工厂正在启动一个功能:

            Task.Factory.StartNew(() => ServerGetSecureLog(ServerAndProjectorArchive);
    
            private static void ServerGetSecureLog(string archivePath)
            {
                var localClientManager = InitializeConnection();
                var destinationPath = $"{ServerSecureLogFile}";
    
                var result = ServerGetBasicSecureLogAsync(localClientManager);
                var sw = StartStopwatch();
                //Wait upto 120s
                if (!result.Wait(TimeSpan.FromSeconds(120))) // <<< Exception thrown here.
                {
                    StopStopwatch(sw);
                    log.Warn($"{MethodBase.GetCurrentMethod().Name} took too long to execute (timeout exceeded).");
                }
                else
                {
                    StopStopwatch(sw);
    

    问题是,我得到了 System.AggregateException 如上所示被投掷。我一定快疯了。,因为要调试它,我在之前的每一行代码上都设置了断点,在同一行抛出异常,甚至是启动线程的行和调用的lambda,但它们都没有被命中。向上走一个堆栈帧,就可以调用我放置断点的lambda。

    可变状态: local variable state localClientManager 看起来还未初始化,所以IP似乎不知怎么被劫持了。

    我不希望优化器对DEBUG构建做任何事情,并且代码中没有不安全的区域。是什么导致了这种集市行为?

    编辑

    远程调试可能是个问题吗?不幸的是,我无法在该系统上安装调试器,也无法从本地计算机上真正运行应用程序。

    0 回复  |  直到 3 年前
        1
  •  0
  •   Rafael Diego Nicoletti    3 年前

    每当任务在失败状态下运行到完成时,也就是说,当运行该任务的方法以某种方式失败时,它就会抛出AggregateException。

    这是因为任务可以继续:

    var t = SomeAsyncMethod().ContinueWith(a=> { });
    

    如果SomeAsyncMethod抛出异常,ContinueWith也抛出异常,则聚合异常将具有该调用的所有异常。

    然而,当您使用async/await调用并尝试/catch时,c#async state会展开聚合异常,并在代码中抛出原始异常。

    代码中的问题与GetServerLog方法是同步的并且正在调用Task方法有关。 您可以:

    var localClientManager = InitializeConnection();
    var destinationPath = $"{ServerSecureLogFile}";
    //Wait upto 120s
    var cts = new CancellationTokenSource(TimeSpan.FromSeconds(120));
    // assumes that this method will look at the token to stop processing and bubbling up a OperationCancelledException/TimeoutException if token expires.
    // localClientManager can be null if InitializeConnection returns null or depends on other lazy/async initialization steps.
    
    var result = ServerGetBasicSecureLogAsync(localClientManager, cts.Token);
    
    var sw = Stopwatch.StartNew();
    try 
    {
        // This can cause deadlocks it Thread pool threads are waiting for a free thread and other locations are doing Waits: https://stackoverflow.com/questions/13140523/await-vs-task-wait-deadlock
    
        //result.WaitOne(TimeSpan.FromSeconds(120));
        result.GetAwaiter().GetResult();
    
    }
    catch(MySimpleException)
    {
    }
    catch(OperationCancelledException)
    {
    }
    finally
    {
       sw.Stop();
        // could enclose cts in using statement
       cts.Dispose();
    }
    
    

    因为GetAwaiter().GetResult()是异步状态调用的相同方法,所以它还展开聚合异常,通过使用try/catch,您也可以查看取消的操作。

    此外,您不需要创建Task来运行异步方法:

    async Task SomeAsyncMethod()
    {
        var localClientManager = InitializeConnection();
        var destinationPath = $"{ServerSecureLogFile}";
        //Wait upto 120s
        var cts = new CancellationTokenSource(TimeSpan.FromSeconds(120));
        // assumes that this method will look at the token to stop processing and bubbling up a OperationCancelledException/TimeoutException if token expires.
        // localClientManager can be null if InitializeConnection returns null or depends on other lazy/async initialization steps.
        var sw = Stopwatch.StartNew();
        try 
        {
            await ServerGetBasicSecureLogAsync(localClientManager, cts.Token);
        }
        catch(MySimpleException)
        {
        }
        catch(OperationCancelledException)
        {
        }
        finally
        {
            sw.Stop();
            // could enclose cts in using statement
           cts.Dispose();
        }
    }
    
    // this call will never throw as long as method is catching and handling exceptions
    SomeAsyncMethod().GetAwaiter().GetResult();