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-interopまたはPInvokeのユーザーマーシャリングエラーがあり、スタックが破損する可能性があります。

すべてのタスクが終了するまで、またはタスクがキャンセルされるまで待機してから、タスクが終了したかキャンセルされたかを示す値を返すにはどうすればよいですか?

4

1 に答える 1

1

CLRのFatalExecutionEngineErrorバグのように聞こえます。最小限の再現を作成し、MicrosoftConnectを介して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 に答える