2009-04-27 8 views
2

このValueStoreクラスはスレッドセーフですか? GetInt(文字列キー)のロックスコープは、利回りを中心に拡張する必要がありますか?このクラスはスレッドセーフですか?

public class ValueStore 
{ 
    private readonly object _locker = new object(); 
    private readonly Dictionary<string, int> _data = 
    new Dictionary<string, int>(); 

    public ValueStore(Dictionary<string, int> data) 
    { 
    _data = data; 
    } 

    public IEnumerable<int> GetInt(string key) 
    { 
    IEnumerable<KeyValuePair<string, int>> selected; 
    lock(_locker) 
    { 
     selected = _data.Where(x => x.Key.Equals(key)); 
    } 

    foreach (KeyValuePair<string, int> pair in selected) 
    { 
     yield return pair.Value; 
    } 
    } 
} 

ユニットテストは大丈夫のようだ:

[TestFixture] 
public class ValueStoreTest 
{ 
    [Test] 
    public void test1() 
    { 
    Dictionary<string, int> data = new Dictionary<string, int>(); 
    for (int i = 0; i < 100000; i++) 
    { 
     data.Add(i.ToString(),i); 
    } 

    ValueStore vs = new ValueStore(data); 

    for (int i = 0; i < 900000; i++) 
    { 
     ThreadPool.QueueUserWorkItem(delegate 
     { 
     for (int j = 0; j < 100000; j++) 
     { 
      IEnumerable<int> d = vs.GetInt(j.ToString()); 
     } 
     }); 
    } 
    } 
} 
+0

ここではスレッドセーフな問題よりも深刻な問題があります。間違った辞書を使用しています。あなたはリストのように使っています。 - キーに複数の値を割り当てることができます。できません。したがって、歩留まりは不要です。 - contains/getメソッドだけでなく、辞書のすべての値を列挙しています。 –

答えて

6

いいえ、それは間違いなく、スレッドセーフではありません。

クライアントによって渡された辞書を使用しているという事実は、クライアントがいつそれを変更するかを制御できないことを意味します。 Where句を適用するときにだけロックすることもありますが、実際には何も繰り返しは実行されません。結果を反復処理しながらロックを保持する必要がありますが、前にも述べたように、クライアントがいつでも辞書を変更するのを止めるわけではありません。

クラス内で辞書を作成し、その中でデータを公開する(つまり外部から保護する)場合、完全にスレッドセーフにすることができます。クライアントコードがディクショナリを変更しないと主張するなら、ディクショナリはライタがないときに複数のスレッドから読み込むことができるので、ロックはまったく必要ありません。

1

ロックが解除されるまで、ロック内のステートメントは実行されないことがわかります。反復処理中にコレクションをロックする必要がある場合は、yieldをlockステートメントに移動します。

+2

ロック*内のステートメントは、ロック内で*実行されます。その文が遅延実行イテレータを返すだけです。 * lambda式*はロックで実行されません。 –

1

いいえ、そうではありません。コンストラクタに渡したオブジェクトDictionary<string, int>の読み込みと書き込みを開始すると、問題が発生します。クラス宣言_dataは、コンストラクターの割り当てによって直ちに上書きされます。

この問題を修正するには、コンストラクタで渡されたDictionaryの各キーと値のペアを、直接割り当てではなくクラスDictionaryにコピーします。

あなたはスレッドセーフだと思いますが、明らかにクラスは読み取り専用です。

関連する問題