2

는 더 나은 TPL에서 예외와 오류 처리의 근거를 파악하기 위해 고군분투 (및 .NET 4.5에서 좀 더 운 비동기/기다리고 작업) 약간 내 이전 질문 "How to better understand the code/statements from "Async - Handling multiple Exceptions" article?" C# 콘솔 응용 프로그램 코드 2를 실행하위 작업의 많은 예외 중 하나만 전파됩니까?

수정 (: 다른에 의해, 미안 하나 개의 질문을 시작했지만 결국 업데이트!) 작업 : 은 내부 중첩 된 부착 (종속)의 아이를 분리

class Program 
{ 
    static void Main(string[] args) 
    { Tst(); 
     Console.ReadLine(); 
    } 
    async static Task Tst() 
    { 
     try 
     { 
      await Task.Factory.StartNew 
      (() => 
       { 
        Task.Factory.StartNew 
         ( () => { 
            Console.WriteLine("From 1st child"); 
            throw new NullReferenceException(); 
            } 
          , TaskCreationOptions.AttachedToParent 
         ); 
       Task.Factory.StartNew 
         (() => 
           { 
            Console.WriteLine("From 2nd child"); 
            throw new ArgumentException(); 
           } 
     ,TaskCreationOptions.AttachedToParent 
         ); 
       } 
      ); 
    } 
    catch (AggregateException ex) 
    { 
     Console.WriteLine("** {0} **", ex.GetType().Name); 
     foreach (var exc in ex.Flatten().InnerExceptions) 
     { 
      Console.WriteLine(exc.GetType().Name); 
     } 
    } 
    catch (Exception ex) 
    { 
     Console.WriteLine("## {0} ##", ex.GetType().Name); 
    } 
} 

는 출력을 생성하는 번갈아 (비 결정적) :

From 1st child 
From 2nd child 
** AggregateException ** 
ArgumentException 

From 1t child 
From 2nd child 
** AggregateException ** 
NullReferenceException 

은 언제나처럼 보인다 항상/전파 잡은 자식 작업 중 하나에서 단 하나 개의 예외입니다.

예외가 전파되는 이유는 무엇입니까?
하위 작업의 예외가 전혀 없거나 모든 예외가 항상 잡히면 더 잘 이해할 수 있습니다.

예외적으로 두 가지 예외가 발생할 수 있습니까?

답변

6

: 이렇게하면 출력을 제공해야합니다. 그들은 함께 갈 수 있도록 설계되지 않았습니다.

svick은 이미 his (correct) answer to your other question의 일부로이 질문에 답변했습니다. 여기에 당신이 생각할 수있는 방법은 다음과 같습니다

  • 각 내부 StartNewAggregateException에 랩 및 반환 Task에 배치 한 가지 예외를 가져옵니다.
  • 바깥 쪽 StartNew은 하위 작업에서 모두 AggregateException을 가져 오며, 이는의 AggregateException으로 바뀝니다.
  • awaitTask 때 첫 번째 내부 예외가 발생합니다. 다른 것은 무시됩니다.
당신은 예외가 await에 의해 제기 된 후 Task의를 저장하고이를 검사하여이 동작을 관찰 할 수

: 당신이 WriteLine에 중단 점을 넣으면

async static Task Test() 
{ 
    Task containingTask, nullRefTask, argTask; 
    try 
    { 
     containingTask = Task.Factory.StartNew(() => 
     { 
      nullRefTask = Task.Factory.StartNew(() => 
      { 
       throw new NullReferenceException(); 
      }, TaskCreationOptions.AttachedToParent); 
      argTask = Task.Factory.StartNew(() => 
      { 
       throw new ArgumentException(); 
      }, TaskCreationOptions.AttachedToParent); 
     }); 
     await containingTask; 
    } 
    catch (AggregateException ex) 
    { 
     Console.WriteLine("** {0} **", ex.GetType().Name); 
    } 
} 

, 당신은 모두의 예외 것을 볼 수 있습니다 하위 작업이 상위 작업에 배치됩니다. await 연산자는 그 중 하나만 전파하므로 사용자는 그 중 하나만 잡습니다.

+1

이 문제의 추론에 대한 자세한 내용은 Stephen Toub의 기사 [*. NET 4.5 *에서의 작업 예외 처리] (http://blogs.msdn.com/b/pfxteam/archive/2011/)의 후반부를 참조하십시오. 09/28/10217876.aspx). – svick

-1

나는 이것이 발생하는 이유를 추론 할 수있는 것은 그 작업이 완료 될 때까지 기다리는 신호를 기다리고 있다는 것입니다. 예외가 발생하면 예외가 발생하여 작업이 완료되고 예외가 발생하면 비동기 함수로 예외가 전파됩니다. 즉,이 설정으로 인해 항상 한 가지 예외가 발생합니다.

둘 다 항상 잡으려면 기다리고 대신 Task.Factory.StartNew (..)를 사용하십시오. Wait(); Wait 함수는 모든 하위 프로세스의 수를 유지하며 모든 하위 프로세스가 완료 될 때까지 리턴하지 않습니다. 복수의 예외 (각 아이로부터 1 개)가 슬로우되기 (위해) 때문에, 새로운 AggregateException에 번들됩니다.이 예외는 나중에 캐치되어 그 아이는 평탄화되어 내부 예외가 인쇄됩니다. 당신은 async으로 상위/하위 작업을 혼합해서는 안

From 1st child 
From 2nd child 
** AggregateException ** 
ArgumentException 
NullReferenceException 
관련 문제