2013-09-30 75 views
1

我有一個對象A從中我想用對象的B方法執行新線程。我可以使用Task.CreateNew等..問題是我不知道如何處理新線程中的異常。內部線程異常處理

我想一般的是,與對象的B法內螺紋拋出異常哪個父對象A將趕上並關閉它的執行,與對象B.沿

  • 我無法添加代碼,掌握循環在所有

  • 完成主循環結束以後,例外是不接受的,我想 趕時間內螺紋例外它發生

有什麼辦法可以實現它嗎?

在下面的代碼我沒有異常處理和主線程繼續:

static void Main() 
{ 
    Console.WriteLine("start"); 
    Task.Factory.StartNew(PrintTime, CancellationToken.None); 

    for (int i = 0; i < 20; i++) 
    { 
     Console.WriteLine("master thread i={0}", i + 1); 
     Thread.Sleep(1000); 
    } 
} 

private static void PrintTime() 
{ 
    for (int i = 0; i < 10; i++) 
    { 
     Console.WriteLine("inner thread i={0}",i+1); 
     Thread.Sleep(1000); 
    } 

    throw new Exception("exception"); 
} 

回答

1

下面的解決方案的工作,無論哪個線程先拋出一個異常:

static void Main() 
{ 
    Console.WriteLine("start"); 

    var innerCts = new CancellationTokenSource(); 
    Exception mainException = null; 
    var mainThread = new Thread(() => SafeMainThread(innerCts, ref mainException)); 
    mainThread.Start(); 

    var innerTask = Task.Factory.StartNew(state => PrintTime(state), 
              innerCts, 
              innerCts.Token, 
              TaskCreationOptions.LongRunning, 
              TaskScheduler.Default); 

    var innerFault = innerTask.ContinueWith(t => { Console.WriteLine("Inner thread caused " + t.Exception.InnerException.GetType().Name + ". Main thread is being aborted..."); mainThread.Abort(); }, 
              TaskContinuationOptions.OnlyOnFaulted); 

    var innerCancelled = innerTask.ContinueWith(_ => Console.WriteLine("Inner thread cancelled."), 
               TaskContinuationOptions.OnlyOnCanceled); 

    var innerSucceed = innerTask.ContinueWith(_ => Console.WriteLine("Inner thread completed."), 
               TaskContinuationOptions.OnlyOnRanToCompletion); 

    try 
    { 
     innerTask.Wait(); 
    } 
    catch (AggregateException) 
    { 
     // Ignore. 
    } 

    mainThread.Join(); 

    Console.ReadLine(); 
} 

private static void SafeMainThread(CancellationTokenSource innerCts, ref Exception mainException) 
{ 
    try 
    { 
     MainThread(); 
     Console.WriteLine("Main thread completed."); 
    } 
    catch (ThreadAbortException) 
    { 
     Console.WriteLine("Main thread aborted."); 
    } 
    catch (Exception exception) 
    { 
     Console.WriteLine("Main thread caused " + exception.GetType().Name + ". Inner task is being canceled..."); 

     innerCts.Cancel(); 
     mainException = exception; 
    } 
} 

private static void MainThread() 
{ 
    for (int i = 0; i < 20; i++) 
    { 
     Console.WriteLine("master thread i={0}", i + 1); 
     Thread.Sleep(500); 
    } 
    throw new Exception("exception"); 
} 

private static void PrintTime(object state) 
{ 
    var cts = (CancellationTokenSource)state; 

    for (int i = 0; i < 10; i++) 
    { 
     cts.Token.ThrowIfCancellationRequested(); 

     Console.WriteLine("inner thread i={0}", i + 1); 
     Thread.Sleep(500); 
    } 

    throw new Exception("exception"); 
} 
2

保留你的任務實例的引用,並調用Wait它,當你準備好處理它的結果。在任務執行期間拋出的任何未處理的內部異常將被包裝在一個AggregateException中,而該方法又從Wait方法中拋出。

static void Main() 
{ 
    Console.WriteLine("start"); 
    Task task = Task.Factory.StartNew(PrintTime, CancellationToken.None); 

    for (int i = 0; i < 20; i++) 
    { 
     Console.WriteLine("master thread i={0}", i + 1); 
     Thread.Sleep(1000); 

     // Stop iterating in case of unhandled exception in inner task. 
     if (task.Status == TaskStatus.Faulted) 
      break; 
    } 

    try 
    { 
     task.Wait(); 
    } 
    catch (AggregateException ae) 
    { 
     ae.Handle((x) => 
     { 
      Console.WriteLine("Exception: " + x.ToString()); 
     }); 
    } 
} 
+0

這意味着主線程必須完成以檢查異常,而我想終止內線程異常的任何線程 – eugeneK

+0

@eugeneK:我編輯了我的答案,以防止在發生內部異常時進行迭代。即使在1000毫秒的延時結束之前,這可以進一步改進以停止主線程。 – Douglas

+0

雖然我不能改變主迴路, – eugeneK

0

嘗試攔截內部異常,並在主迴路檢查它的值,這將是一個取消請求:

static void Main() 
{ 
    Console.WriteLine("start"); 

    try 
    { 
     AggregateException innerException = null; 

     Task.Factory.StartNew(PrintTime, CancellationToken.None) 
        .ContinueWith(t => innerException = t.Exception, TaskContinuationOptions.OnlyOnFaulted); 

     for (int i = 0; i < 20; i++) 
     { 
      if (innerException != null) 
       throw innerException; 

      Console.WriteLine("master thread i={0}", i + 1); 
      Thread.Sleep(1000); 
     } 
    } 
    catch (AggregateException) 
    { 
     Console.WriteLine("Inner thread caused exception. Main thread handles that exception."); 
    } 
} 
+0

我不能這樣做在主循環... – eugeneK

0

你可以嘗試和運行異常的發生,異常處理程序。您可以使用一個標誌,我已經使用了異常檢查異常occurence本身的例子:

private static AggregateException exception = null; 

    static void Main(string[] args) 
    { 
     Console.WriteLine("Start"); 

     Task.Factory.StartNew(PrintTime, CancellationToken.None).ContinueWith(HandleException, TaskContinuationOptions.OnlyOnFaulted); 

     for (int i = 0; i < 20; i++) 
     { 
      Console.WriteLine("Master Thread i={0}", i + 1); 
      Thread.Sleep(1000); 
      if (exception != null) 
      { 
       break; 
      } 
     } 

     Console.WriteLine("Finish"); 
     Console.ReadLine(); 
    } 

    private static void HandleException(Task task) 
    { 
     exception = task.Exception; 
     Console.WriteLine(exception); 
    } 

    private static void PrintTime() 
    { 
     for (int i = 0; i < 10; i++) 
     { 
      Console.WriteLine("Inner Thread i={0}", i + 1); 
      Thread.Sleep(1000); 
     } 

     throw new Exception("exception"); 
    } 
+0

我不能在主循環中執行 – eugeneK

0

如果您不能修改主體的內部,我不知道怎麼去細粒度控制它。此刻我看到的解決方案是將主體包裝到管理線程,允許放棄它,如果內螺紋拋出一個異常:

static void Main() 
{ 
    Console.WriteLine("start"); 

    var mainThread = new Thread(MainThread); 
    mainThread.Start(); 

    var task = Task.Factory 
        .StartNew(PrintTime) 
        .ContinueWith(t => { Console.WriteLine("Inner thread caused exception. Main thread is being aborted."); mainThread.Abort(); }, 
           TaskContinuationOptions.OnlyOnFaulted); 
    task.Wait(); 

    Console.WriteLine("Waiting for main thread to abort..."); 
    mainThread.Join(); 
    Console.WriteLine("Main thread aborted."); 

    Console.ReadLine(); 
} 

private static void MainThread() 
{ 
    for (int i = 0; i < 20; i++) 
    { 
     Console.WriteLine("master thread i={0}", i + 1); 
     Thread.Sleep(1000); 
    } 
} 

private static void PrintTime() 
{ 
    for (int i = 0; i < 10; i++) 
    { 
     Console.WriteLine("inner thread i={0}", i + 1); 
     Thread.Sleep(1000); 
    } 

    throw new Exception("exception"); 
} 
+0

如果主線程崩潰的異常,是不是我的代碼有未處理的異常? – eugeneK

+0

你還沒有寫,答案應該考慮到主線程的異常。但是好的,我可以解決這個問題,並且擺脫主線程比內線程更長的假設,並且考慮到兩個線程都會在不拋出異常的情況下完成任務的情況。 –

+0

對不起我的錯,將盡快檢查它 – eugeneK