0

この例外を引き起こす条件を再現しようとしています:

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 を使用していますが、例外処理のコードを書いていません。その結果、その例外が発生します。現在、別のプログラムで同じ条件を再作成して、観察されていない例外を実験しようとしています。

4

6 に答える 6

4

ファイナライザーは独自のスレッドで実行されるため、GC.Collect() の後に GC.WaitForPendingFinalizers() への呼び出しを追加する必要がある場合があります。

于 2010-12-22T05:57:49.967 に答える
3

例外はTaskExceptionHolderのファイナライザーによってスローされるため、この例外がスローされる前にファイナライザー スレッドを実行する必要があります。Josh が指摘しているように、 を呼び出して、それが起こるのを待つことができますCG.WaitForPedingFinalizers()

現在の Async CTP では、この動作が変更されていることに注意してください。今年の初めに TechEd Europe で PFX チームの Stephen Toub と話をしたところ、新しい非同期機能が正しく動作するように変更する必要があるとのことでした。したがって、フレームワークの次のバージョンについて何かを言うのはまだ時期尚早ですが、この動作は次のバージョンで変更される可能性があります。

于 2010-12-22T10:22:41.863 に答える
1

@Sly、あなたは有効な答えを思いつきましたが、エラーメッセージの提案「... Waiting on the Task ...」に注意することで、ほとんどの人はより良いサービスを受けることができると思います. GC アクティビティに参加するということは、GC をよく知っていてパフォーマンスのボトルネックを抱えているか、要点を見逃しているかのいずれかの兆候です。私の場合、それは後者を意味します;) StartNew 呼び出しは Task を返すので、なぜそれを使用しないのですか? 例えば

Task myTask = Task.Factory.StartNew(() => { throw new NullReferenceException("ex"); }); // タスクが完了するまでしばらく待ちます
myTask.Wait();

于 2011-01-13T21:19:59.137 に答える
0

タスクの完了後にコードを適切に呼び出そうとしなかったことに本当に驚いています。どのプロセスも 3 秒以内に完了すると誰が言えるでしょうか? それだけでなく、他のプロセスを完全に 3 秒間拘束します。その実装を ContinueWith() タスク メソッドに置き換えて、タスクの完了後に GC を呼び出します。

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

完了するまでブロックする必要がある場合 (デバッグに使用していたサンプル コードの場合)、タスクの開始後に WaitOne を実行し、ContinueWith() で待機ハンドラーにシグナルを送ることもできます。本番コードでこれを行う必要がある場合、達成しようとしているのは実際には同期であり、タスクの使用についてまったく心配する必要はありません。

于 2011-11-01T18:00:00.063 に答える
-1

エラーを再現する最も簡単な方法は、タスクが完了するのを待つことです。

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

wait を呼び出すと、タスクの実行が完了するまで呼び出しがブロックされます。

于 2012-03-28T06:23:21.630 に答える
-1

私は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"); 
        }
    }
}
于 2011-01-10T20:56:27.470 に答える