4

入力に対して順次処理を実行するコンポーネントを作成しています。いくつかの異なるプロセスでホストされるため、スレッドセーフにする必要があります。最初は、コードから意図的にスレッド セーフを除外しました。今回はそれを紹介します。

まず、最初からエラーを発生させたかったのですが、できませんでした。以下は、処理エンジンのコードの簡略化されたバージョンです。

public Document DoOrchestration(Document input)
{
    Document output = new Document();

    foreach (var orchestrationStep in m_OrchestrationSteps)
    {
        var processor = GetProcessor(orchestrationStep).Clone();

        output = processor.Process(input);

        input = output;
    }

    return output;
}

プロセッサは私の組織内の他の人によって開発される可能性があり、これには複雑な初期化が含まれる場合があります。これらはスレッド アンセーフである可能性もあるため、プロトタイプ パターンを使用して一意のインスタンスを取得し、それらのスレッド化の問題を回避します。

この機能をテストするために、次のコードを使用しました。

for (int i = 0; i < 20000; i++)
{
    Thread t = new Thread(() => TestOrchestration(i));
    t.Start();
}

void TestOrchestration(int number)
{
    Document doc = new Document(string.Format("Test {0}", number));
    doc = DoOrchestration(doc);
    if (doc.ToString().Substring(0,35) != strExpectedResult)
    {
        System.Console.WriteLine("Error: {0}", doc.ToString();
    }
}

一部のスレッドが別のスレッドと衝突し、結果が混同されると予想していましたが、驚いたことに、そうはなりませんでした。

これにはおそらく簡単で論理的な説明がありますが、私にはわかりません。それとも、コードが単純すぎて、2 つのスレッドが同時に入力/出力変数をいじるという結果になるのでしょうか?

4

4 に答える 4

1

チェスをチェックしてください。

CHESS は、並列プログラムで Heisenbugs を見つけて再現するためのツールです。CHESS は並行テストを繰り返し実行し、実行ごとに異なるインターリーブが行われるようにします。インターリーブによってエラーが発生した場合、CHESS はインターリーブを再現してデバッグを改善できます。CHESS は、マネージド プログラムとネイティブ プログラムの両方で使用できます。

于 2012-10-19T06:40:41.140 に答える
0

次のスレッドが始まる前に、テスト機能はほぼ完了していると思います。オーケストレーション関数を呼び出す前に、すべてのスレッドをManualResetEventSlimで待機させてから、ManualResetEventSlimを設定
できます。これにより、すべてのスレッドが実際に同時にオーケストレーションを呼び出そうとします。

また、すべてのスレッドの男性オーケストラシオンがほぼ同時に呼び出す場合、この動作をシミュレートするために20,000スレッドは必要ない可能性があります。

ManualResetEventSlim manualEvent = new ManualResetEventSlim (false);

for (int i = 0; i < 20000; i++)
{
    Thread t = new Thread(() => TestOrchestration(i));
    t.Start();
}
manualEvent.Set();

void TestOrchestration(int number)
{
    manualEvent.Wait();
    Document doc = new Document(string.Format("Test {0}", number));
    doc = DoOrchestration(doc);
    if (doc.ToString().Substring(0,35) != strExpectedResult)
    {
        System.Console.WriteLine("Error: {0}", doc.ToString();
    }
}
于 2012-10-19T06:49:38.757 に答える
0

テスト関数が単純であるため、前のスレッドが作業を完了する前に、スレッドが大量に生成される時間すら得られないと思います。バリアを使用して、計算ステップを開始する前にすべてのスレッドを生成できるようにすることを検討してください。また、たとえば、同じループで同じ操作をいくつか実行するなどして、テスト ケースの複雑さを増すことを検討する必要があります (スレッドの開始はコストが高く、他のコアが作業を完了する前に作業を完了することができます)。リソース競合。

一般に、リソースの競合は、同じリソースに長期間にわたって迅速にアクセスすることによって引き起こされる可能性がありますが、テスト ケースではこれが許可されていないようです。余談ですが、後で導入するのではなく、スレッド セーフを考慮して設計することを強くお勧めします。コードを操作するときは、後の段階でコードを分析するときよりも、リソース アクセス パターンをよりよく理解できます。

于 2012-10-19T06:43:41.593 に答える
0

ManualResetEvent任意の数の待機中のスレッドを同時に継続するために使用できます。

于 2012-10-19T09:45:49.653 に答える