0

我调用了一个异步方法,该方法又调用需要启动几个异步操作。

一旦所有异步操作完成,我需要通知调用者操作是完成还是取消。代码如下所示。它似乎一直有效,直到它因 FatalExecutionEngineError 而崩溃。我不打任何 P/invoke 或不安全的电话。

   public class Fetcher
    {
        private List<ItemsBoundToUI> uiItems;
        public async Task<bool> Fetch()
        {
            List<Task> currentlyRunningTasks = new List<Task>();


                var src = new CancellationTokenSource();


                foreach (var channel in this.uiItems)
                {
                    var task = FetchForItem(channel, src.Token);
                    currentlyRunningTasks.Add(task);
                }

            bool wasCancelled = await Task.Factory.ContinueWhenAll(currentlyRunningTasks.ToArray(),
                                                                    (s) =>
                                                                    {
                                                                        bool wasC = s.Any(ss => ss.IsCanceled);

                                                                        return wasC;
                                                                    }
                                                                    );


           return !wasCancelled;
        }

        private async Task FetchForItem(ItemsBoundToUI channel, CancellationToken src)
        {
            var subitems = await dataRepository.GetSubItemsAsync(channel.ID);

            if (src.IsCancellationRequested)
                return;
            channel.SubItems = subitems;
        }
    }

错误消息说

运行时遇到致命错误。错误地址位于线程 0xd94 上的 0x6c108144。错误代码为 0xc0000005。此错误可能是 CLR 中的错​​误或用户代码的不安全或不可验证部分中的错误。此错误的常见来源包括 COM 互操作或 PInvoke 的用户封送错误,这可能会损坏堆栈。

怎么可能等到所有任务都完成,或者直到它们被取消,然后返回一个值来指示它们是完成还是被取消?

4

1 回答 1

1

FatalExecutionEngineError听起来像一个CLR错误。请开发一个最小的复制并通过Microsoft Connect向 Microsoft 报告。

最好让取消按照设计的方式工作(通过例外)。对于await多个任务,请使用Task.WhenAll.

public class Fetcher
{
  private List<ItemsBoundToUI> uiItems;
  public async Task<bool> Fetch()
  {
    List<Task> currentlyRunningTasks = new List<Task>();
    var src = new CancellationTokenSource();
    foreach (var channel in this.uiItems)
    {
      var task = FetchForItem(channel, src.Token);
      currentlyRunningTasks.Add(task);
    }

    try
    {
      await Task.WhenAll(currentlyRunningTasks);
      return true;
    }
    catch (OperationCanceledException)
    {
      return false;
    }
  }

  private async Task FetchForItem(ItemsBoundToUI channel, CancellationToken src)
  {
    var subitems = await dataRepository.GetSubItemsAsync(channel.ID);
    src.ThrowIfCancellationRequested();
    channel.SubItems = subitems;
  }
}
于 2012-05-21T02:10:15.243 回答