2010-07-19 26 views
21

Tôi đang đọc qua một cuốn sách về Thư viện song song nhiệm vụ C# và có ví dụ sau nhưng trình xử lý TaskScheduler.UnobservedTaskException không bao giờ được kích hoạt. Bất cứ ai có thể cho tôi bất kỳ manh mối nào về lý do tại sao?TaskScheduler.UnobservedTaskException xử lý sự kiện không bao giờ được kích hoạt

TaskScheduler.UnobservedTaskException += (object sender, UnobservedTaskExceptionEventArgs eventArgs) => 
{ 
    eventArgs.SetObserved(); 
    ((AggregateException)eventArgs.Exception).Handle(ex => 
    { 
     Console.WriteLine("Exception type: {0}", ex.GetType()); 
     return true; 
    }); 
}; 

Task task1 = new Task(() => 
{ 
    throw new ArgumentNullException(); 
}); 

Task task2 = new Task(() => { 
    throw new ArgumentOutOfRangeException(); 
}); 

task1.Start(); 
task2.Start(); 

while (!task1.IsCompleted || !task2.IsCompleted) 
{ 
    Thread.Sleep(5000); 
} 

Console.WriteLine("done"); 
Console.ReadLine(); 
+3

Cuốn sách đó là gì? –

+0

Tôi cũng rất tò mò - ví dụ này là không chính xác, vì không thể đưa ra sự kiện trong ví dụ này ... –

+1

Đây là cuốn sách: http://www.apress.com/book/view/1430229675 Pro .NET 4 Lập trình song song trong C# – devlife

Trả lời

34

Thật không may, ví dụ đó sẽ không bao giờ hiển thị cho bạn mã của bạn. Các UnobservedTaskException sẽ chỉ xảy ra nếu một nhiệm vụ được thu thập bởi GC với một ngoại lệ unobserved - miễn là bạn giữ một tham chiếu đến task1task2, GC sẽ không bao giờ thu thập, và bạn sẽ không bao giờ thấy xử lý ngoại lệ của bạn.

Để xem hành vi của các UnobservedTaskException trong hành động, tôi muốn thử như sau (ví dụ contrived):

public static void Main() 
{ 
    TaskScheduler.UnobservedTaskException += (object sender, UnobservedTaskExceptionEventArgs eventArgs) => 
       { 
        eventArgs.SetObserved(); 
        ((AggregateException)eventArgs.Exception).Handle(ex => 
        { 
         Console.WriteLine("Exception type: {0}", ex.GetType()); 
         return true; 
        }); 
       }; 

    Task.Factory.StartNew(() => 
    { 
     throw new ArgumentNullException(); 
    }); 

    Task.Factory.StartNew(() => 
    { 
     throw new ArgumentOutOfRangeException(); 
    }); 


    Thread.Sleep(100); 
    GC.Collect(); 
    GC.WaitForPendingFinalizers(); 

    Console.WriteLine("Done"); 
    Console.ReadKey(); 
} 

này sẽ cho bạn thấy tin nhắn của bạn. Cuộc gọi Thread.Sleep(100) đầu tiên cung cấp đủ thời gian cho các nhiệm vụ cần thực hiện. Việc thu thập và chờ đợi buộc một bộ sưu tập GC, mà sẽ cháy xử lý sự kiện của bạn 2x.

+0

Điều đó giải thích nó. Cảm ơn! – devlife

+6

Trong .NET 4.5, bạn cần thêm voodoo để điều này xảy ra. Đầu tiên, bạn cần kích hoạt [ThrowUnobservedTaskException] (http://msdn.microsoft.com/en-GB/library/jj160346.aspx) trong app.config, và thứ hai, bạn cần xây dựng mã trong cấu hình Release (một điểm chỉ được ghi lại trong phần Ví dụ của bài viết MSDN được liên kết). Tôi đổ lỗi cho điều này "chúng ta hãy ngăn chặn ngoại lệ âm thầm" tâm lý trên JavaScript trong trình duyệt :) –

+2

@romkyns, tôi không cần phải làm điều này cho ứng dụng .NET 4.5 của mình. –

3

Ngoại lệ sẽ không bị "bỏ ghi chú" trong đoạn mã mẫu đó. Không cho đến khi bộ thu gom rác thoát khỏi các phiên bản Tác vụ. Bạn sẽ phải viết lại như sau:

class Program { 
    static void Main(string[] args) { 

     TaskScheduler.UnobservedTaskException += (object sender, UnobservedTaskExceptionEventArgs eventArgs) => 
     { 
      eventArgs.SetObserved(); 
      ((AggregateException)eventArgs.Exception).Handle(ex => 
      { 
       Console.WriteLine("Exception type: {0}", ex.GetType()); 
       return true; 
      }); 
     }; 

     Run(); 

     GC.Collect(); 
     GC.WaitForPendingFinalizers(); 

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

    static void Run() { 
     Task task1 = new Task(() => { 
      throw new ArgumentNullException(); 
     }); 

     Task task2 = new Task(() => { 
      throw new ArgumentOutOfRangeException(); 
     }); 

     task1.Start(); 
     task2.Start(); 

     while (!task1.IsCompleted || !task2.IsCompleted) { 
      Thread.Sleep(50); 
     } 
    } 
} 

Đừng làm điều này, sử dụng Task.Wait().

0

tôi chạy mã này trên NET 4.5, Visual Studio 2012 (gỡ lỗi hoặc Thả, không quan trọng), tôi đã làm không đặt ThrowUnobservedTaskException trong app.config của tôi:

using System; 
using System.Threading; 
using System.Threading.Tasks; 

namespace Test 
{ 
    public static class Program 
    { 
     private static void Main() 
     { 
      TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException; 

      RunTask(); 

      Thread.Sleep(2000); 

      GC.Collect(); 
      GC.WaitForPendingFinalizers(); 
      GC.Collect(); 

      Console.ReadLine(); 
     } 

     static void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e) 
     { 
      Console.WriteLine("Caught!"); 
     } 

     private static void RunTask() 
     { 
      Task<int> task = Task.Factory.StartNew(() => 
      { 
       Thread.Sleep(1000); // emulate some calculation 
       Console.WriteLine("Before exception"); 
       throw new Exception(); 
       return 1; 
      }); 
     } 
    } 
} 

Và ngoại trừ bị xử lý bởi UnobservedTaskException ("Caught!" được in).

+0

Điều này là do 'ThrowUnobservedTaskException 'chỉ cần thiết nếu bạn muốn hoàn nguyên hành vi 4.0 của một ngoại lệ Task kết thúc quá trình. Trong 4.5, mặc định được thay đổi thành * không * chấm dứt quá trình. Nó không được yêu cầu đối với trường hợp ngoại lệ không được quan sát trong ví dụ của bạn để bị xử lý sự kiện bắt gặp. Thông tin thêm trong các nhận xét [ở đây] (http://msdn.microsoft.com/en-us/library/system.threading.tasks.taskscheduler.unobservedtaskexception% 28v = vs.110% 29.aspx) – BitMask777

Các vấn đề liên quan