1

関連:ThreadPool.QueueUserWorkItemからの例外をキャッチする方法は?

ThreadPool.QueueUserWorkItem()によって開始されたバックグラウンドスレッドで例外をキャッチし、共有インスタンス変数を介してそれらをメインスレッドに伝播しています。

バックグラウンドスレッドはこれを行います:

try
{
    ... stuff happens here...
}
catch (Exception ex1)
{
    lock(eLock) 
    {
        // record only the first exception
        if (_pendingException == null) 
            _pendingException = ex1;
    }
}

_pendingException(複数のバックグラウンドスレッド)には複数の潜在的なライターがいるため、ロックで保護します。

メインスレッドでは、読む前にロックを取得する必要があり_pendingExceptionますか?または私は単にこれを行うことができます:

if (_pendingException != null)
    ThrowOrHandle(); 

編集:
ps:リーダースレッドはホットパス上にあるため、ロックを取得したくないので、ロックを頻繁に取得および解放します。

4

3 に答える 3

3

あなたはこれを簡単に逃れることができないでしょう。リーダーが既存のスレッドを処理する前に別のスレッドが例外をスローすると、例外が失われます。ここで必要なのは同期キューです。

試す
{{
    ...ここで何かが起こります...
}
キャッチ(例外ex1)
{{
    ロック(キュー)
    {{
        queue.Enqueue(ex1);
        Monitor.PulseAll(queue);
    }
}

そしてそれを処理するには:

while(!stopped)
    ロック(キュー)
    {{
        while(queue.Count> 0)
            processException(queue.Dequeue());
        Monitor.Wait(queue);
    }
于 2009-11-04T01:44:36.573 に答える
2

参照への読み取りと書き込みはアトミックであり ( C# Specを参照)、lock がメモリ バリアを作成することはほぼ確実なので、実行していることはおそらく安全です。

しかし、実際には読み取りの周りにロックを使用してください。動作することが保証されています。ロックでアクセスされていない場合は、何かが間違っていることがわかります。ロックがパフォーマンスの問題を引き起こしている場合は、フラグを頻繁にチェックしていることになり、それは「正しいこと」です。

于 2009-11-05T04:30:13.517 に答える
1

最初の例外だけに関心がある場合でも、少なくとも 2 つの理由でロックを使用したい場合があります。

  1. マルチコア CPU では、変数を volatile にしない (またはメモリ バリア操作を実行しない) と、異なるコアで実行されているスレッドが異なる値を参照する瞬間が発生する可能性があります。(ただし、ワーカースレッドを呼び出すとメモリバリア操作が発生するかどうかはわかりません)。lock(queue) (更新)lock(queue)以下のコメントで Eric が指摘したように、ワーカー スレッドを呼び出すとメモリ バリア操作が発生します。

2.参照はアドレスではないことに注意してください(Eric Lippert 著) (参照が原子的に読み取ることができる 32 ビット CLR の 32 ビット アドレスであると想定している場合)。参照の実装は、CLR の将来のリリースでアトミックに読み取られない可能性があるいくつかの不透明な構造に変更される可能性があり (予見可能な将来に発生する可能性は低いと思いますが:))、コードが壊れます。

于 2009-11-04T23:18:04.923 に答える