2012-02-27 8 views
8

私はマルチスレッドアプリケーションを作成しており、単体テストの記述方法を工夫しています。私はそれがおそらく最善の方法についての別の質問だと思う。単体テストでのスレッドの安全性の判断

public class MyClass 
{ 
    private List<string> MyList = new List<string>(); 

    public void Add(string Data) 
    { 
     MyList.Add(Data); //This is not thread safe!! 
    } 
} 
+5

を余裕があると同じくらいの品質です

**そのコードはスレッドセーフかどうか、スレッドセーフのいずれかです。 –

+0

@DavidHeffernanうーん.....助けて! – Jon

+0

ほとんどの場合、コードについて推論することで、この種の検証を行う必要があります。Marcが説明しているテストの種類は非常に便利で、多くのメリットがあります。しかし、彼らは何かを証明するのには不十分です。 –

答えて

11

何かがスレッドセーフであることを証明するのは難しいです。おそらくは問題が起きにくいでしょう。競合状態が発生しやすいこと、または競合状態が発生しにくいことを示すことができます。しかし、競合状態を生み出さないということは、それがそこにないということを意味するものではない。

しかし、私の通常のアプローチは、スレッドセーフでなければならないコードがあると思うのであれば、単一のManualResetEventの背後にある多くのスレッドをスピンアップさせることです。ゲートに到達する最後のスレッド(カウントに連動して使用)は、ゲートを開いて、すべてのスレッドが同時にシステムにヒットするようにします(すでに存在しています)。その後、彼らは作業を行い、正常な終了条件をチェックします。それから私はこのプロセスを何度も繰り返す。これは、疑わしいスレッド競合を再現し、「明らかに壊れている」から「明白な方法で壊れていない」(「壊れていない」とは決定的に異なる)ことを示すのに十分です。

メモ:ほとんどのコードはスレッドセーフである必要はありません。

+0

ありがとうございますが、スレッドベースのコードをたくさん書いて、ユニットテスト/ TDDのように、私たちのものはスレッドセーフでなければなりません。 – Jon

+0

@Markデモコードはありますか? – Jon

+0

Marc、あなたが書いたことは非常に興味深いですが、残念ながらそれはあまり明確ではありません。あなたのプロセスをより詳細に記述したいと思いますが、「ゲートに到達する最後のスレッド(カウントに連動して使用)」や「ゲートを開く」といったいくつかの点に明瞭さを追加したいのですか? –

4

スレッドの安全性、そのことにより、あなたは確実にテストできるものではありません。とにかく、私は、そのスレッドセーフとユニットテストでそれを証明したいが、それを行う方法を考え出すことができないではないが、知っている以下のようなクラスを持っています性質は非決定論的です。別のスレッドで同じ操作を数百回並列に実行し、結果が一貫しているかどうかを確認することができます。それほど素晴らしいわけではありませんが、私が想像するものよりも優れています。

+0

MS Researchには、C#のカスタムスレッドスケジューラを使用して、すべての衝突ポイントを特定するランナーが1回ありました;)引き出されました(プロダクト化が保留されており、MS resarcharchからもうダウンロードできません)。問題は、すべての可能な組み合わせを検証するためにそのタイプのツールが必要であることです。数回の実行で非常に難しいものもあります。 – TomTom

+0

@TomTom興味深いですね。それは生産のような何かを見ることはいいですね。 – spencercw

+0

@spencercw合意。私はこれが本当に必要だと思います! – Jon

7

私はしばしば、コードの一部がスレッドセーフであることを証明する単体テストを書いています。通常、私は生産時に見つかったバグに対応してこれらのテストを書いています。この場合、テストの目的は、バグが複製されていること(テストが失敗している)、新しいコードがスレッドの問題を修正したこと(テストパス)を示し、その後のリリースの回帰テストとして機能することを示します。

私が書いたテストのほとんどはスレッドの競合状態をテストしていますが、スレッドのデッドロックもテストしています。

コードが積極的にユニットテストされているのは、スレッドセーフです。少し難解です。単体テストは書くのが難しいわけではありませんが、スレッドが安全でない可能性のあるものを判断するためには、しっかりとした分析が必要です。分析が正しい場合は、コードスレッドを安全にするまで失敗するテストを書くことができます。

スレッド競合状態のためにテストする場合は、私のテストはほとんど常に同じパターンに従って

:(これは擬似コードです)

boolean failed = false; 
int iterations = 100; 

// threads interact with some object - either 
Thread thread1 = new Thread(new ThreadStart(delegate() { 
    for (int i=0; i<iterations; i++) { 
    doSomething(); // call unsafe code 
    // check that object is not out of synch due to other thread 
    if (bad()) { 
     failed = true; 
    } 
    } 
}); 
Thread thread2 = new Thread(new ThreadStart(delegate() { 
    for (int i=0; i<iterations; i++) { 
    doSomething(); // call unsafe code 
    // check that object is not out of synch due to other thread 
    if (bad()) { 
     failed = true; 
    } 
    } 
}); 

thread1.start(); 
thread2.start(); 
thread1.join(); 
thread2.join(); 
Assert.IsFalse(failed, "code was thread safe"); 
+0

ジョインがスレッドの待機を行わないため、ジョインを正しくテストする方法別のものが実行される前に実行するために実行しますか? – Jon

+2

@ジョン:「開始()は、」スレッド1とスレッド2の両方で呼び出されると、彼らは実行を開始。 )(参加だけで両方のスレッドが結果を確認するために行われるまで待機するように、メインスレッド(ユニットテストを実行している)に指示します。スレッド1とスレッド2は、ものが「レース」であり、それらはそれぞれ、彼らは確実に悪い状態にテストコードを配置します繰り返しのいくつかの数の後、スレッド安全でないコードを呼び出すとき。 join()が終了すると、メインスレッドはテストが成功したか失敗したかを確認できます。 –

3

私がしようとすると、スレッドの問題を検出するためのユニットテストをあきらめました。私はハードウェア(ハードウェアがあるとしばしば自分の仕事があり、ネットワーク上にはuControllersがある場合)とフラットアウトを実行する不当に多数の自動化されたクライアントを持つシステム負荷テストを使用します。私は他のことをしている間、それを1週間走らせておく。週末に荷物を取り除き、何が残っているかを確認します。それでも動作している場合、オブジェクトが漏れておらず、メモリが大幅に増加していない場合、私はそれを出荷します。私は:)あなたが証明**に単体テストを使用することはできません一般的なルールとして

関連する問題