Dựa trên nghiên cứu của tôi, tôi đã học được những điều sau đây:TaskScheduler.UnobservedTaskException không bao giờ được gọi
TaskScheduler.UnobservedTaskException
phải đợi cho nhiệm vụ được thu gom rác thải trước khi ngoại lệ không quan sát được của nhiệm vụ đó sẽ bong bóng lên đến sự kiệnUnobservedTaskException
.- Nếu bạn đang sử dụng
Task.Wait()
, nó sẽ không bao giờ được gọi, bởi vì bạn đang chặn kết quả sắp xảy ra từ Tác vụ, do đó ngoại lệ sẽ được ném trênTask.Wait()
thay vì bong bóng lên đến sự kiệnUnobservedException
. - Gọi
GC.Collect()
theo cách thủ công thường là ý tưởng tồi trừ khi bạn biết chính xác mình đang làm gì, do đó tốt trong trường hợp này là xác nhận mọi thứ, nhưng không phải là giải pháp thích hợp cho vấn đề.
Vấn đề
Nếu thoát ứng dụng của tôi trước khi thu gom rác đá vào, tôi hoàn toàn 100% có thể không nhận được sự kiện UnobservedTaskException
tôi để bắn.
Lưu ý đoạn mã sau:
class Program
{
static void Main(string[] args)
{
TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;
Task.Factory.StartNew(() =>
{
Console.WriteLine("Task started.");
throw new Exception("Test Exception");
});
Thread.Sleep(1000);
//GC.Collect();
//GC.WaitForPendingFinalizers();
}
static void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
{
File.WriteAllText(@"C:\data\TestException.txt", e.Exception.ToString());
Console.WriteLine("EXCEPTION UNOBSERVED");
}
}
Không có tập tin ngoại lệ được viết và không có gì được ghi vào giao diện điều khiển. 10-15 phút và nhiều hơn nữa có thể đi sau khi các ứng dụng thoát và vẫn còn tôi thấy không có bằng chứng rằng phần còn lại của ứng dụng của tôi là rác thu thập được. Bạn có thể hỏi, tại sao không chỉ thu thập khi xuất cảnh? Vâng, kịch bản thế giới thực của tôi là bẫy ngoại lệ của tôi chạy bên trong một dịch vụ WCF được lưu trữ bên trong một dịch vụ Windows. Tôi không thể bẫy khi dịch vụ Windows tắt (và do đó theo cách thủ công gọi GC.Collect()
) vì không có sự kiện nào cho đến mức tôi có thể thấy.
Tôi làm sai ở đâu? Làm thế nào để đảm bảo rằng nếu một cái gì đó sâu bên trong dịch vụ WCF là cuối cùng sẽ phá vỡ dịch vụ cửa sổ của tôi, rằng tôi có một cơ hội để đăng nhập ngoại lệ trước khi dịch vụ rơi hơn?
Xin chào, cảm ơn đề xuất, mặc dù tôi thực sự đã chạy nó bên ngoài trình gỡ lỗi.Tôi cũng nhận thấy bạn đang sử dụng GC.Collect(). Điều gì xảy ra trong ví dụ của bạn nếu bạn không tự thu thập? –
@Nathan: Thông thường, không có đủ áp lực GC để bao giờ có điều này xảy ra trong ví dụ đơn giản này. Nếu GC không thu thập, "nhiệm vụ" sẽ không nhấn finalizer, và UnobservedException không bao giờ cháy. Nó chỉ xảy ra khi finalizer thu thập một nhiệm vụ unrooted với một ngoại lệ. –
@Nathan: Lưu ý rằng UnobservedTaskException sẽ không ngăn ứng dụng tắt trong mọi trường hợp - bạn cần xử lý các ngoại lệ bên trong nhiệm vụ của mình hoặc luôn chờ nhiệm vụ, nếu bạn muốn ngăn điều này tắt ứng dụng. –