簡體   English   中英

如何使用TPL導致AggregateException?

[英]How to cause AggregateException with TPL?

我正在嘗試重新創建將導致此異常的條件:

System.AggregateException: A Task's exception(s) were not observed 
either by Waiting on the Task or accessing its Exception property. 
As a result, the unobserved exception was rethrown by the finalizer thread.`

我寫這個程序的原因是我會引起異常,但它不會:

using System;
using System.Threading.Tasks;
namespace SomeAsyncStuff
{
    class Program
    {
        static void Main(string[] args)
        {
            Task.Factory.StartNew(() => { throw new NullReferenceException("ex"); });
            GC.Collect();
            Console.WriteLine("completed");            
        }
    }
}

在我的實際應用程序中,我使用TPL,但沒有編寫我的異常處理權限。 結果我得到了例外。 現在,我試圖在一個單獨的程序中重新創建相同的條件,以嘗試觀察不到的異常。

您可能需要在GC.Collect()之后添加對GC.WaitForPendingFinalizers()的調用,因為終結器在它們自己的線程上運行。

該異常由TaskExceptionHolder的終結器拋出,因此終結器線程必須在拋出此異常之前運行。 正如Josh所指出的,您可以通過調用CG.WaitForPedingFinalizers()來等待。

請注意,此行為已在當前的異步CTP中更改。 我今年早些時候在TechEd Europe上與PFX團隊的Stephen Toub進行了交談,他表示必須更改它才能使新的異步功能正常工作。 因此,盡管現在說下一個框架的下一個版本還為時過早,但是在即將發布的版本中很可能會改變這種行為。

@Sly,盡管您想出了一個有效的答案,但我認為大多數人最好還是聽從錯誤消息建議“ ...等待任務...”。 參與GC活動是您熟悉GC並存在性能瓶頸的信號,或者您錯過了要點。 在我的情況下,這意味着后者;)StartNew調用的確會返回一個Task,那么為什么不使用它呢? 例如

任務myTask = Task.Factory.StartNew(()=> {拋出新的NullReferenceException(“ ex”);}); //給完成任務一些時間
myTask.Wait();

我真的很驚訝您沒有嘗試在任務完成后正確調用代碼,因為誰能說任何進程將在3秒內完成? 不僅如此,而且還占用了其他整個過程3秒鍾的時間。 我將用ContinueWith()任務方法替換該實現,以在任務完成后調用GC。

Task.Factory
    .StartNew(() => { throw new NullReferenceException("ex"); })
    .ContinueWith(p => GC.Collect());

如果在完成之前需要阻塞(對於用於調試的示例代碼),也可以在啟動任務后執行WaitOne並讓ContinueWith()通知等待處理程序。 如果您必須在生產代碼中執行此操作,那么也許您想要完成的實際上是同步的,而您根本不必擔心使用任務。

我是OP。 我測試了GC.WaitForPendingFinalizers(),但它沒有幫助重新創建異常。 問題在於任務開始之前已執行了GC.Collect()。

這是重新創建異常的正確代碼:

using System;
using System.Threading;
using System.Threading.Tasks;
namespace SomeAsyncStuff
{
    class Program
    {
        static void Main(string[] args)
        {
            Task.Factory.StartNew(() => { throw new NullReferenceException("ex"); });

            // give some time to the task to complete
            Thread.Sleep(3000);

            GC.Collect();
            // GC.WaitForPendingFinalizers();
            Console.WriteLine("completed"); 
        }
    }
}

重新創建錯誤的最簡單方法是等待任務完成。

Task task = Task.Factory.StartNew(() => { throw new NullReferenceException("ex"); });
//this is where the exception will be thrown
task.Wait();

呼叫等待將阻塞呼叫,直到任務完成執行。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM