【问题标题】:Run Tasks In Parallel While Maintaining Option To Cancel Them And Do Something When Everything Finishes并行运行任务,同时保留取消任务并在一切完成后执行某些操作的选项
【发布时间】:2012-05-27 13:23:02
【问题描述】:

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

所有异步操作完成后,我需要通知调用者操作是完成还是取消。代码如下所示。它似乎一直有效,直到它因 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-interop 或 PInvoke 的封送处理错误,这可能会损坏 堆栈。

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

【问题讨论】:

  • 不是你所看到的答案,但如果你想返回它是否被取消,为什么不直接返回 src.IsCancellationRequested? FWIW,在 FetchForItem 方法中调用 CancellationToken 'src' 似乎很奇怪 :)

标签: .net windows-8 async-await c#-5.0


【解决方案1】:

FatalExecutionEngineError 听起来像是一个 CLR 错误。请开发一个最小的repro 并通过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;
  }
}

【讨论】:

  • 没有取消就存在问题。我急需解决问题。
  • 如果您迫切需要 Beta 平台的解决方法,最好的选择是联系 Microsoft。不要忘记您的 MSDN 订阅包括一些支持票。
  • P.S. 0xC0000005 是访问冲突。使用经过验证的托管代码不可能出现此错误;它只能是不正确的 p/Invoke、不安全代码或非托管代码的结果。您的解决方案中是否有任何 p/Invoke、不安全或非托管代码?
  • 不,没有。但是,我搜索了 MSDN 论坛,看来这可能是一个 CLR 错误。希望它会在 RC 中得到修复。
猜你喜欢
  • 1970-01-01
  • 2020-08-10
  • 1970-01-01
  • 1970-01-01
  • 2014-10-11
  • 1970-01-01
  • 1970-01-01
  • 2019-02-22
  • 1970-01-01
相关资源
最近更新 更多